Commit 074e8bf
authored
fix: honor distance_threshold=0 in semantic cache and message history (#650)
Fixes #649
### Problem
The per-call `distance_threshold` override was resolved with a
truthiness check:
```python
distance_threshold = distance_threshold or self._distance_threshold
```
`0.0` is falsy, so a caller passing `distance_threshold=0`
(exact-match-only) had it silently replaced by the instance default and
received fuzzy cache hits instead. `0` is a valid threshold everywhere
else: `set_threshold()` accepts `0 <= x <= 2` and
`VectorRangeQuery.set_distance_threshold()` rejects only negatives.
The failure mode is a false cache hit so the caller gets a cached
response to a prompt they never asked, believing fuzzy matching was off.
### Fix
Fall back to the configured default only when the override is `None`.
Applied in `SemanticCache.check()`, `SemanticCache.acheck()`, and
`SemanticMessageHistory.get_relevant()`.
### Tests
Added `test_check_with_zero_distance_threshold` and
`test_acheck_with_zero_distance_threshold` to
`tests/integration/test_llmcache.py`. Each stores a prompt, asserts a
near-paraphrase does **not** hit at `distance_threshold=0`, and asserts
it **does** hit at the cache default (so the test fails for the right
reason rather than by accident).
Verified against the real suite (Python 3.12, Redis 8.4 via the repo's
compose fixture):
- before the fix: both new tests fail with `AssertionError: assert
[{'entry_id': ...}] == []`
- after the fix: both pass
- full `tests/integration/test_llmcache.py`: **62 passed**
### Scope note
I left the `ttl = ttl or self._ttl` occurrences alone. A TTL of 0 isn't
meaningful in Redis and the suite already rejects it (`test_bad_ttl`),
so the falsy-fallback is harmless there. Happy to widen the scope if
maintainers prefer consistency.
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Low Risk**
> Small, targeted behavior fix in lookup paths with clear regression
tests; no API or schema changes beyond honoring an already-valid
threshold value.
>
> **Overview**
> Fixes a bug where per-call **`distance_threshold`** overrides used
`distance_threshold or self._distance_threshold`, so **`0`**
(exact-match-only in Redis COSINE distance) was treated as unset and
replaced by the instance default—causing **false cache hits** and fuzzy
context when callers intended strict matching.
>
> **`SemanticCache.check()`**, **`SemanticCache.acheck()`**, and
**`SemanticMessageHistory.get_relevant()`** now fall back to the
configured default only when the override is **`None`**.
>
> Integration tests cover sync/async cache checks and semantic history
retrieval: near-paraphrases must not match at
**`distance_threshold=0`**, while the same queries still match at the
default threshold.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
5620780. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->1 parent 788f368 commit 074e8bf
4 files changed
Lines changed: 63 additions & 6 deletions
File tree
- redisvl/extensions
- cache/llm
- message_history
- tests/integration
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
398 | 398 | | |
399 | 399 | | |
400 | 400 | | |
401 | | - | |
402 | | - | |
| 401 | + | |
| 402 | + | |
| 403 | + | |
| 404 | + | |
403 | 405 | | |
404 | 406 | | |
405 | 407 | | |
| |||
491 | 493 | | |
492 | 494 | | |
493 | 495 | | |
494 | | - | |
495 | | - | |
| 496 | + | |
| 497 | + | |
| 498 | + | |
| 499 | + | |
496 | 500 | | |
497 | 501 | | |
498 | 502 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
231 | 231 | | |
232 | 232 | | |
233 | 233 | | |
234 | | - | |
235 | | - | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
236 | 238 | | |
237 | 239 | | |
238 | 240 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
577 | 577 | | |
578 | 578 | | |
579 | 579 | | |
| 580 | + | |
| 581 | + | |
| 582 | + | |
| 583 | + | |
| 584 | + | |
| 585 | + | |
| 586 | + | |
| 587 | + | |
| 588 | + | |
| 589 | + | |
| 590 | + | |
| 591 | + | |
| 592 | + | |
| 593 | + | |
| 594 | + | |
| 595 | + | |
| 596 | + | |
| 597 | + | |
| 598 | + | |
| 599 | + | |
| 600 | + | |
| 601 | + | |
| 602 | + | |
| 603 | + | |
| 604 | + | |
| 605 | + | |
| 606 | + | |
580 | 607 | | |
581 | 608 | | |
582 | 609 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
606 | 606 | | |
607 | 607 | | |
608 | 608 | | |
| 609 | + | |
| 610 | + | |
| 611 | + | |
| 612 | + | |
| 613 | + | |
| 614 | + | |
| 615 | + | |
| 616 | + | |
| 617 | + | |
| 618 | + | |
| 619 | + | |
| 620 | + | |
| 621 | + | |
| 622 | + | |
| 623 | + | |
| 624 | + | |
| 625 | + | |
| 626 | + | |
| 627 | + | |
| 628 | + | |
| 629 | + | |
| 630 | + | |
| 631 | + | |
| 632 | + | |
609 | 633 | | |
610 | 634 | | |
611 | 635 | | |
| |||
0 commit comments