@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 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
- await Promise.allSettled([...pending]);
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({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sigrun/recall",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "Cross-conversation recall extension for sigrun (pi-durable)",
5
5
  "type": "module",
6
6
  "engines": {