@sigrun/recall 0.1.1 → 0.1.3
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.
- package/CHANGELOG.md +17 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +13 -2
- package/dist/route.js +3 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,23 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## [0.1.3] - 2026-11-03
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- The search route accepts `?exclude=<conversationId>` so callers can reproduce auto-recall's exclusion of the current conversation (eval fidelity).
|
|
12
|
+
- The eval harness (`scripts/recall-eval.ts`) supports a per-pair `exclude` field with client-side filtering, and over-fetches when excluding so filtered hits don't consume the top-k window.
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
|
|
16
|
+
- (from polish wave 1, 0.1.2) The shutdown drain is bounded and its race timer clears on fast settles.
|
|
17
|
+
|
|
18
|
+
## [0.1.2] - Unreleased
|
|
19
|
+
|
|
20
|
+
### Fixed
|
|
21
|
+
|
|
22
|
+
- Bound the shutdown drain: each round races `Promise.allSettled(pending)` against a timer for the remaining budget, so a capture whose embedding fetch never settles can no longer hang `harnessShutdown` past the 30s deadline; the database still closes.
|
|
23
|
+
|
|
7
24
|
## [0.1.1] - Unreleased
|
|
8
25
|
|
|
9
26
|
### Fixed
|
package/dist/index.d.ts
CHANGED
|
@@ -3,6 +3,8 @@ import { RecallDb } from "./db.js";
|
|
|
3
3
|
export interface FactoryDeps {
|
|
4
4
|
openDb?: (path: string) => RecallDb;
|
|
5
5
|
now?: () => number;
|
|
6
|
+
/** Test seam: fetch implementation for the embeddings endpoint. */
|
|
7
|
+
fetchImpl?: typeof fetch;
|
|
6
8
|
}
|
|
7
9
|
/**
|
|
8
10
|
* The loader injects the host only when factory.length > 0: keep the host
|
package/dist/index.js
CHANGED
|
@@ -37,7 +37,7 @@ export default function createRecall(host, deps = {}) {
|
|
|
37
37
|
return {};
|
|
38
38
|
const key = JSON.stringify(settings.embedding);
|
|
39
39
|
if (embedder === undefined || embeddingKey !== key) {
|
|
40
|
-
embedder = createEmbedder(settings.embedding, () => host.stores.secrets.get("embedding-api-key"));
|
|
40
|
+
embedder = createEmbedder(settings.embedding, () => host.stores.secrets.get("embedding-api-key"), deps.fetchImpl);
|
|
41
41
|
embeddingKey = key;
|
|
42
42
|
}
|
|
43
43
|
return {
|
|
@@ -206,7 +206,18 @@ export default function createRecall(host, deps = {}) {
|
|
|
206
206
|
harnessShutdown: async () => {
|
|
207
207
|
const deadline = Date.now() + 30_000;
|
|
208
208
|
while (pending.size > 0 && Date.now() < deadline) {
|
|
209
|
-
|
|
209
|
+
const remaining = deadline - Date.now();
|
|
210
|
+
// A capture promise may never settle (a hung embedding fetch); race
|
|
211
|
+
// each round against the remaining budget so the drain always
|
|
212
|
+
// returns by the deadline. The losing timer is cleared so the
|
|
213
|
+
// common fast-settle case leaves no live timer behind.
|
|
214
|
+
let timer;
|
|
215
|
+
await Promise.race([
|
|
216
|
+
Promise.allSettled([...pending]),
|
|
217
|
+
new Promise((resolve) => {
|
|
218
|
+
timer = setTimeout(() => resolve([]), remaining);
|
|
219
|
+
}),
|
|
220
|
+
]).finally(() => clearTimeout(timer));
|
|
210
221
|
}
|
|
211
222
|
database?.close();
|
|
212
223
|
database = undefined;
|
package/dist/route.js
CHANGED
|
@@ -11,9 +11,12 @@ export function createRoutes(deps) {
|
|
|
11
11
|
const url = new URL(request.url);
|
|
12
12
|
const requested = Number(url.searchParams.get("limit") ?? 20);
|
|
13
13
|
const limit = Number.isFinite(requested) ? Math.max(1, Math.min(100, Math.trunc(requested))) : 20;
|
|
14
|
+
const exclude = Number(url.searchParams.get("exclude"));
|
|
15
|
+
const excludeConversation = Number.isInteger(exclude) && exclude > 0 ? exclude : undefined;
|
|
14
16
|
const hits = await deps.searcher.search(url.searchParams.get("q") ?? "", {
|
|
15
17
|
current: { conversationId: undefined, owner: ctx.principal.user },
|
|
16
18
|
model: undefined,
|
|
19
|
+
excludeConversation,
|
|
17
20
|
includeJobs: true,
|
|
18
21
|
}, limit);
|
|
19
22
|
return Response.json({
|