Skip to content

fix(memory): avoid first-turn cold stalls - #1828

Merged
yyhhyyyyyy merged 6 commits into
devfrom
fix/memory-first-turn-cold-start
Jun 28, 2026
Merged

fix(memory): avoid first-turn cold stalls#1828
yyhhyyyyyy merged 6 commits into
devfrom
fix/memory-first-turn-cold-start

Conversation

@yyhhyyyyyy

@yyhhyyyyyy yyhhyyyyyy commented Jun 27, 2026

Copy link
Copy Markdown
Collaborator

Move cold vector-store opening off the recall hot path,bundle and smoke DuckDB VSS across build/release flows, and add targeted warm metadata checks plus cooldown coverage.

Summary by CodeRabbit

  • New Features

    • Added background prewarming for active agents to reduce first-turn latency.
    • Improved embedding-dimension tracking so vector-store warmup is more reliable and can recover automatically when embedding settings change.
    • Enhanced DuckDB VSS runtime bundling and loading for packaged apps, including architecture-aware verification on macOS/Windows/Linux.
  • Bug Fixes

    • Strengthened packaged reliability by failing closed when bundled VSS artifacts are missing or can’t load, while keeping safer development fallback.
  • Documentation / Tests

    • Expanded cold-start latency documentation and added cross-platform CI smoke tests to validate load-by-path/base64 behaviors.

@coderabbitai

coderabbitai Bot commented Jun 27, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The PR updates DuckDB VSS packaging, workflow verification, and MemoryPresenter warm/readiness logic to use embedding-dimension metadata and bundled extension loading.

Changes

Memory cold-start and bundled VSS

Layer / File(s) Summary
Docs and runtime scripts
docs/issues/memory-first-turn-cold-start/spec.md, docs/issues/memory-first-turn-cold-start/plan.md, docs/issues/memory-first-turn-cold-start/tasks.md, package.json, scripts/installVss.js, scripts/smoke-duckdb-vss.js, scripts/afterPack.js, test/main/scripts/installVss.test.ts, test/main/scripts/afterPack.test.ts
The docs describe the cold-start and bundled VSS flow, package scripts add platform-specific install commands, and the install/smoke/afterPack scripts download, validate, materialize, and load bundled extensions with tests for parsing, retries, footer validation, and macOS encoding.
Workflow VSS checks
.github/workflows/build.yml, .github/workflows/prcheck.yml, .github/workflows/release.yml, .github/workflows/windows-arm64-e2e.yml, test/main/presenter/pluginPresenter.test.ts
The build, PR check, release, and Windows ARM64 workflows install DuckDB VSS per target platform and architecture, run smoke verification, and update macOS runner selection and artifact-path checks.
Embedding-dimension contract
src/main/presenter/index.ts, src/main/presenter/memoryPresenter/types.ts, src/main/presenter/sqlitePresenter/tables/agentMemory.ts, test/main/presenter/agentMemoryTable.test.ts, test/main/presenter/fakes/memoryFakes.ts, test/main/presenter/memoryPresenter.test.ts, test/main/presenter/memory-persona-eval.test.ts, test/main/presenter/memoryAdd.test.ts, test/main/presenter/memoryRetrieval.eval.test.ts
The presenter API exposes getDimensions, the repository port adds embedding-dimension lookups and staleness checks, SQLite implements the queries, and the related fakes and tests use the new shape.
Warmup and cold-path retrieval
src/main/presenter/memoryPresenter/index.ts, test/main/presenter/memoryPresenter.test.ts
MemoryPresenter adds startup prewarm timers, per-agent warm state tracking, retrieval and consolidation warm checks, and cleanup paths that await and clear warm state on shutdown, disposal, and resource cleanup.
Bundled VSS loading
src/main/presenter/memoryPresenter/memoryVectorStore.ts, test/main/presenter/memoryVectorStore.test.ts
MemoryVectorStore closes partially opened DuckDB handles on create failure and switches bundled VSS loading between packaged fail-closed behavior and development fallback.

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~90 minutes

Possibly related PRs

Poem

I hopped through builds where VSS did sleep,
Then woke the store from bundled deep.
With warm little paws and timer chimes,
I nibbled cold starts into springtime. 🐇

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 2.70% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and accurately summarizes the main memory latency fix in the changeset.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/memory-first-turn-cold-start

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 9

🧹 Nitpick comments (1)
test/main/presenter/memoryPresenter.test.ts (1)

78-99: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Pin the “current” row with explicit timestamps.

Both embedded fixtures inherit createdAt = 1000 from FakeRepository, so getCurrentEmbeddingDimension('a', 'p:m') returns 4 only because insertion order happens to win. Give current and wrong-dim distinct timestamps so this test keeps proving the intended winner once the SQLite lookup is ordered.

Suggested fix
     repo.insert({
       id: 'current',
       agentId: 'a',
       kind: 'semantic',
-      content: 'current vector'
+      content: 'current vector',
+      createdAt: 2_000
     })
@@
     repo.insert({
       id: 'wrong-dim',
       agentId: 'a',
       kind: 'semantic',
-      content: 'wrong dimension'
+      content: 'wrong dimension',
+      createdAt: 1_000
     })
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/main/presenter/memoryPresenter.test.ts` around lines 78 - 99, The test
setup for getCurrentEmbeddingDimension in memoryPresenter.test.ts relies on
insertion order because both embedded rows share the same createdAt from
FakeRepository. Update the fixtures around repo.insert and repo.updateStatus for
the current and wrong-dim records so they have explicit, distinct timestamps,
with current pinned as the intended latest winner, and keep using the existing
repository methods and getCurrentEmbeddingDimension expectation to verify the
SQLite ordering behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/build.yml:
- Around line 79-83: The DuckDB VSS smoke checks in the workflow only validate
the workspace copy before packaging, so they miss regressions in the packaged
app. Move or add a post-build verification step that runs against the unpacked
Electron artifacts/resources for each OS and arch, using the existing
install/smoke commands or their equivalent in the build job after packaging, so
the check confirms the bundled VSS asset is actually present.

In @.github/workflows/release.yml:
- Around line 173-177: The current DuckDB VSS Windows checks only validate the
pre-package runtime, so add a post-package verification step in the release
workflow that runs against the built app artifact and confirms VSS is loaded
from the bundled resources path. Update the existing Windows VSS verification
sequence around the Install and verify DuckDB VSS for Windows step (and the
matching release-job blocks it applies to) so it first packages the app, then
smoke-tests the packaged output rather than the runtime install path. Ensure the
new verification explicitly targets the shipped app’s bundled resources to catch
packaging regressions where the extension is missing.

In `@scripts/installVss.js`:
- Around line 128-166: Add a per-attempt timeout inside downloadExtension so a
stalled fetchImpl cannot block the retry loop indefinitely. Update the fetch
call in downloadExtension to use an attempt-scoped timeout signal or wrapper,
and make sure timeout failures are converted into retryable VssDownloadError
instances with the existing retry/backoff flow and onRetry callback. Keep the
change localized to downloadExtension and related timeout helpers/options in
scripts/installVss.js.

In `@scripts/smoke-duckdb-vss.js`:
- Around line 13-25: The parseArgs helper currently accepts flags like
--platform and --arch without an explicit value by falling back to the next argv
entry or host defaults, which can hide miswired smoke commands. Update parseArgs
in the smoke-duckdb-vss script to detect when a long flag is provided without an
inline “=” value and the next argv entry is missing or is another flag, then
fail fast by throwing an error instead of populating options. Keep the behavior
for valid key/value forms unchanged so the CLI only proceeds when required
values are explicitly supplied.

In `@src/main/presenter/memoryPresenter/index.ts`:
- Around line 253-254: Track and cancel pending prewarm timers for a deleted
agent in memoryPresenter’s timer management. The issue is that
cleanupDeletedAgentResources() only drains active warmups and leaves scheduled
entries in prewarmTimers, which can still fire after deletion. Update the
prewarm scheduling logic in memoryPresenter (including the
prewarmStartTimer/prewarmTimers state and the cleanupDeletedAgentResources() /
settleDeletedAgentInFlight() flow) to associate timers with agent IDs, clear any
matching timers before settleDeletedAgentInFlight(), and remove them from the
set so deleted agents cannot be reopened by late prewarm callbacks.

In `@src/main/presenter/memoryPresenter/memoryVectorStore.ts`:
- Around line 71-86: The fallback in MemoryVectorStore’s extension loading path
is still performing a network INSTALL vss from packaged builds when the bundled
extension is missing or fails to load. Update the load logic around the
try/catch in MemoryVectorStore to fail closed in packaged/runtime builds (or
disable vector recall) instead of calling INSTALL/LOAD vss, and keep the network
fallback only for dev/test paths so open does not block on a first-turn
download.

In `@src/main/presenter/sqlitePresenter/tables/agentMemory.ts`:
- Around line 808-820: The current-dimension lookup in
getCurrentEmbeddingDimension is nondeterministic because it uses LIMIT 1 without
an ORDER BY, so SQLite may return an older embedded row. Update this query in
agentMemory to deterministically select the most recent/current matching row,
using a stable sort on a suitable timestamp or primary key field that identifies
the latest embedding record, so the warmup path and fake repository always see
the same embedding_dim.

In `@test/main/presenter/agentMemoryTable.test.ts`:
- Around line 276-280: The current dimension check for
getCurrentEmbeddingDimension is nondeterministic because the underlying
agentMemory.ts query uses LIMIT 1 without an ORDER BY, so the test can alternate
between matching dimensions. Fix this by making the SQLite query in
agentMemory.ts deterministic using a stable ordering, or update the test to
avoid asserting the exact returned dimension and instead only verify the
non-null/stale embedding behavior around getCurrentEmbeddingDimension and
hasStaleEmbeddings.

In `@test/main/presenter/pluginPresenter.test.ts`:
- Around line 1360-1362: The macOS workflow test assertions in
pluginPresenter.test are too broad because the ARM runner check is currently
satisfied by the Intel runner line. Tighten the expectations around the
buildWorkflow string in the affected test cases by asserting the exact macOS
runner entries for both architectures separately, using the existing
buildWorkflow, macos-15-intel, and macos-15 references so the test proves the
ARM runner is actually present.

---

Nitpick comments:
In `@test/main/presenter/memoryPresenter.test.ts`:
- Around line 78-99: The test setup for getCurrentEmbeddingDimension in
memoryPresenter.test.ts relies on insertion order because both embedded rows
share the same createdAt from FakeRepository. Update the fixtures around
repo.insert and repo.updateStatus for the current and wrong-dim records so they
have explicit, distinct timestamps, with current pinned as the intended latest
winner, and keep using the existing repository methods and
getCurrentEmbeddingDimension expectation to verify the SQLite ordering behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3259c2d1-48d2-4667-b56a-b35c6b5362b5

📥 Commits

Reviewing files that changed from the base of the PR and between 77e0541 and b038076.

📒 Files selected for processing (23)
  • .github/workflows/build.yml
  • .github/workflows/prcheck.yml
  • .github/workflows/release.yml
  • .github/workflows/windows-arm64-e2e.yml
  • docs/issues/memory-first-turn-cold-start/plan.md
  • docs/issues/memory-first-turn-cold-start/spec.md
  • docs/issues/memory-first-turn-cold-start/tasks.md
  • package.json
  • scripts/installVss.js
  • scripts/smoke-duckdb-vss.js
  • src/main/presenter/index.ts
  • src/main/presenter/memoryPresenter/index.ts
  • src/main/presenter/memoryPresenter/memoryVectorStore.ts
  • src/main/presenter/memoryPresenter/types.ts
  • src/main/presenter/sqlitePresenter/tables/agentMemory.ts
  • test/main/presenter/agentMemoryTable.test.ts
  • test/main/presenter/fakes/memoryFakes.ts
  • test/main/presenter/memory-persona-eval.test.ts
  • test/main/presenter/memoryAdd.test.ts
  • test/main/presenter/memoryPresenter.test.ts
  • test/main/presenter/memoryRetrieval.eval.test.ts
  • test/main/presenter/pluginPresenter.test.ts
  • test/main/scripts/installVss.test.ts

Comment thread .github/workflows/build.yml
Comment thread .github/workflows/release.yml
Comment thread scripts/installVss.js
Comment thread scripts/smoke-duckdb-vss.js Outdated
Comment thread src/main/presenter/memoryPresenter/index.ts Outdated
Comment thread src/main/presenter/memoryPresenter/memoryVectorStore.ts Outdated
Comment thread src/main/presenter/sqlitePresenter/tables/agentMemory.ts
Comment thread test/main/presenter/agentMemoryTable.test.ts
Comment thread test/main/presenter/pluginPresenter.test.ts Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@test/main/presenter/memoryVectorStore.test.ts`:
- Around line 192-195: Avoid hard-coding the Linux-only extension name in the
fs.existsSync mock used by memoryVectorStore.test.ts. Update the mock around the
MemoryVectorStore.loadVss path so it detects the bundled extension file via the
same suffix logic the implementation uses (vss${extensionSuffix}) or otherwise
matches the extension filename dynamically, ensuring the “missing extension”
branch is exercised on macOS, Windows, and Linux. Keep the existing spyOn(fs,
'existsSync') setup, but make the false case derive from the actual extension
suffix rather than a fixed .duckdb_extension string.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5de1cfc2-a167-4aea-8650-df7a3eecea6d

📥 Commits

Reviewing files that changed from the base of the PR and between b038076 and a83d643.

📒 Files selected for processing (17)
  • .github/workflows/build.yml
  • .github/workflows/release.yml
  • docs/issues/memory-first-turn-cold-start/plan.md
  • docs/issues/memory-first-turn-cold-start/spec.md
  • docs/issues/memory-first-turn-cold-start/tasks.md
  • scripts/installVss.js
  • scripts/smoke-duckdb-vss.js
  • src/main/presenter/memoryPresenter/index.ts
  • src/main/presenter/memoryPresenter/memoryVectorStore.ts
  • src/main/presenter/sqlitePresenter/tables/agentMemory.ts
  • test/main/presenter/agentMemoryTable.test.ts
  • test/main/presenter/fakes/memoryFakes.ts
  • test/main/presenter/memoryPresenter.test.ts
  • test/main/presenter/memoryVectorStore.test.ts
  • test/main/presenter/pluginPresenter.test.ts
  • test/main/scripts/installVss.test.ts
  • tsconfig.node.tsbuildinfo
✅ Files skipped from review due to trivial changes (2)
  • docs/issues/memory-first-turn-cold-start/spec.md
  • docs/issues/memory-first-turn-cold-start/tasks.md
🚧 Files skipped from review as they are similar to previous changes (6)
  • test/main/presenter/fakes/memoryFakes.ts
  • .github/workflows/release.yml
  • src/main/presenter/sqlitePresenter/tables/agentMemory.ts
  • test/main/presenter/pluginPresenter.test.ts
  • src/main/presenter/memoryPresenter/index.ts
  • test/main/presenter/memoryPresenter.test.ts

Comment thread test/main/presenter/memoryVectorStore.test.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
test/main/presenter/memoryVectorStore.test.ts (1)

156-160: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Make these packaged-VSS path mocks separator-agnostic.

Both endsWith('/runtime/...') checks only match POSIX paths. On Windows, path.join() produces \, so these tests stop forcing the .gz branch and can fail for the wrong reason. This reintroduces the same cross-platform mock fragility that was fixed earlier in this file.

Suggested fix
-      if (filePath.endsWith('/runtime/duckdb/extensions/vss.duckdb_extension')) return false
-      if (filePath.endsWith('/runtime/duckdb/extensions/vss.duckdb_extension.gz')) return true
+      if (/[/\\]runtime[/\\]duckdb[/\\]extensions[/\\]vss\.duckdb_extension$/.test(filePath)) {
+        return false
+      }
+      if (/[/\\]runtime[/\\]duckdb[/\\]extensions[/\\]vss\.duckdb_extension\.gz$/.test(filePath)) {
+        return true
+      }

Also applies to: 385-389

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/main/presenter/memoryVectorStore.test.ts` around lines 156 - 160, The
`memoryVectorStore.test.ts` mocks for packaged VSS paths are hardcoded with
POSIX separators, so they can miss on Windows and stop exercising the intended
`.gz` branch. Update the `vi.spyOn(fs, 'existsSync')` mocks to match path
separators in a separator-agnostic way, using the same approach consistently in
both affected blocks so the checks work regardless of how `path.join()` formats
the extension paths.
🧹 Nitpick comments (1)
src/main/presenter/memoryPresenter/memoryVectorStore.ts (1)

23-25: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Rename the new module constants to SCREAMING_SNAKE_CASE.

extensionName, gunzipAsync, and packagedVssMaterializationPromises are new top-level constants in a src/**/*.ts file, so they should follow the repo’s constant naming rule. As per coding guidelines, src/**/*.{ts,tsx}: Constants should use SCREAMING_SNAKE_CASE naming.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/presenter/memoryPresenter/memoryVectorStore.ts` around lines 23 -
25, The new top-level constants in memoryVectorStore.ts do not follow the repo’s
constant naming rule. Rename extensionName, gunzipAsync, and
packagedVssMaterializationPromises to SCREAMING_SNAKE_CASE, and update any
references within memoryVectorStore or related helpers so the module still works
with the new names.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@scripts/smoke-duckdb-vss.js`:
- Around line 111-127: The DuckDB smoke test cleanup is scoped too narrowly, so
a failure in `DuckDBInstance.create`/`instance.connect` can leave the native
instance open. Refactor `scripts/smoke-duckdb-vss.js` so the `duckdb`,
`instance`, and `connection` handles are declared outside the inner block and
all cleanup happens in one shared `finally`, closing each handle conditionally
only if it was created successfully.

---

Duplicate comments:
In `@test/main/presenter/memoryVectorStore.test.ts`:
- Around line 156-160: The `memoryVectorStore.test.ts` mocks for packaged VSS
paths are hardcoded with POSIX separators, so they can miss on Windows and stop
exercising the intended `.gz` branch. Update the `vi.spyOn(fs, 'existsSync')`
mocks to match path separators in a separator-agnostic way, using the same
approach consistently in both affected blocks so the checks work regardless of
how `path.join()` formats the extension paths.

---

Nitpick comments:
In `@src/main/presenter/memoryPresenter/memoryVectorStore.ts`:
- Around line 23-25: The new top-level constants in memoryVectorStore.ts do not
follow the repo’s constant naming rule. Rename extensionName, gunzipAsync, and
packagedVssMaterializationPromises to SCREAMING_SNAKE_CASE, and update any
references within memoryVectorStore or related helpers so the module still works
with the new names.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a8b4ff47-1942-409f-a994-b7833fd98041

📥 Commits

Reviewing files that changed from the base of the PR and between d68691f and cfb4a06.

📒 Files selected for processing (12)
  • .github/workflows/build.yml
  • .github/workflows/release.yml
  • docs/issues/memory-first-turn-cold-start/plan.md
  • docs/issues/memory-first-turn-cold-start/spec.md
  • docs/issues/memory-first-turn-cold-start/tasks.md
  • scripts/afterPack.js
  • scripts/smoke-duckdb-vss.js
  • src/main/presenter/memoryPresenter/memoryVectorStore.ts
  • test/main/presenter/memoryVectorStore.test.ts
  • test/main/presenter/pluginPresenter.test.ts
  • test/main/scripts/afterPack.test.ts
  • test/main/scripts/installVss.test.ts
✅ Files skipped from review due to trivial changes (3)
  • docs/issues/memory-first-turn-cold-start/tasks.md
  • docs/issues/memory-first-turn-cold-start/spec.md
  • docs/issues/memory-first-turn-cold-start/plan.md
🚧 Files skipped from review as they are similar to previous changes (4)
  • .github/workflows/build.yml
  • .github/workflows/release.yml
  • test/main/scripts/installVss.test.ts
  • test/main/presenter/pluginPresenter.test.ts

Comment thread scripts/smoke-duckdb-vss.js Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
scripts/afterPack.js (1)

206-208: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Fail the macOS pack step when the VSS source asset is missing.

Line 206 silently returns if app.asar.unpacked/.../vss.duckdb_extension is absent. That lets a macOS package complete without generating the .b64 payload, which defeats the bundled-VSS fail-closed behavior this PR is adding.

Suggested fix
   if (!(await pathExists(extensionPath))) {
-    return
+    throw new Error(`[afterPack] missing macOS DuckDB VSS extension: ${extensionPath}`)
   }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/afterPack.js` around lines 206 - 208, The macOS pack flow in
afterPack.js currently exits early when extensionPath is missing, which lets the
package succeed without the VSS asset. Update the afterPack logic around the
pathExists check to fail the pack step instead of returning silently when the
vss.duckdb_extension source file is absent, so the bundled-VSS path cannot
complete without generating the .b64 payload.
src/main/presenter/memoryPresenter/memoryVectorStore.ts (1)

71-72: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Make failure cleanup close handles independently.

Line 72 relies on close(), but close() wraps connection and instance cleanup in one try; if connection.closeSync() throws, dbInstance.closeSync() is skipped and the native instance can leak.

Suggested fix
   async close(): Promise<void> {
-    try {
-      if (this.connection) this.connection.closeSync()
-      if (this.dbInstance) this.dbInstance.closeSync()
-    } catch (error) {
-      console.error('[MemoryVectorStore] close error', error)
-    }
+    for (const closeHandle of [
+      () => this.connection?.closeSync(),
+      () => this.dbInstance?.closeSync()
+    ]) {
+      try {
+        closeHandle()
+      } catch (error) {
+        console.error('[MemoryVectorStore] close error', error)
+      }
+    }
   }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/presenter/memoryPresenter/memoryVectorStore.ts` around lines 71 -
72, The failure cleanup in memoryVectorStore’s catch block only calls
store.close(), but the current close() path can skip native instance cleanup if
connection.closeSync() throws. Update the cleanup flow so connection and db
instance teardown are handled independently, ensuring dbInstance.closeSync()
still runs even when connection.closeSync() fails, and keep the catch-side
cleanup in memoryVectorStore resilient to either failure.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@scripts/smoke-duckdb-vss.js`:
- Around line 76-80: The temp directory created in the materialization helper is
leaked if any step fails before returning, so make the cleanup happen even when
base64 decode, gunzip, or write throws. Update the materialization flow around
the helper that creates materializedDir and the caller in main so the temp dir
is tracked as soon as mkdtempSync succeeds and is removed in a finally/cleanup
path regardless of whether extensionPath is returned.

In `@src/main/presenter/memoryPresenter/memoryVectorStore.ts`:
- Around line 97-104: The cache fast path in memoryVectorStore.ts returns
targetPath from getCachedExtension without verifying the file contents, so a
tampered DuckDB extension could be loaded. Update getCachedExtension to compare
the on-disk bytes at targetPath against the packaged asset bytes (or their
digest) before returning, and apply the same validation in the race-win branch
after ensureDir/mkdir so only an exact match is reused; use the existing
createHash, VSS_EXTENSION_NAME, and getCachedExtension flow to locate the fix.

---

Outside diff comments:
In `@scripts/afterPack.js`:
- Around line 206-208: The macOS pack flow in afterPack.js currently exits early
when extensionPath is missing, which lets the package succeed without the VSS
asset. Update the afterPack logic around the pathExists check to fail the pack
step instead of returning silently when the vss.duckdb_extension source file is
absent, so the bundled-VSS path cannot complete without generating the .b64
payload.

In `@src/main/presenter/memoryPresenter/memoryVectorStore.ts`:
- Around line 71-72: The failure cleanup in memoryVectorStore’s catch block only
calls store.close(), but the current close() path can skip native instance
cleanup if connection.closeSync() throws. Update the cleanup flow so connection
and db instance teardown are handled independently, ensuring
dbInstance.closeSync() still runs even when connection.closeSync() fails, and
keep the catch-side cleanup in memoryVectorStore resilient to either failure.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 487e39cc-ac14-4caf-a689-e703e397057e

📥 Commits

Reviewing files that changed from the base of the PR and between cfb4a06 and a18174e.

📒 Files selected for processing (12)
  • .github/workflows/build.yml
  • .github/workflows/release.yml
  • docs/issues/memory-first-turn-cold-start/plan.md
  • docs/issues/memory-first-turn-cold-start/spec.md
  • docs/issues/memory-first-turn-cold-start/tasks.md
  • scripts/afterPack.js
  • scripts/smoke-duckdb-vss.js
  • src/main/presenter/memoryPresenter/memoryVectorStore.ts
  • test/main/presenter/memoryVectorStore.test.ts
  • test/main/presenter/pluginPresenter.test.ts
  • test/main/scripts/afterPack.test.ts
  • test/main/scripts/installVss.test.ts
✅ Files skipped from review due to trivial changes (3)
  • docs/issues/memory-first-turn-cold-start/plan.md
  • docs/issues/memory-first-turn-cold-start/spec.md
  • docs/issues/memory-first-turn-cold-start/tasks.md
🚧 Files skipped from review as they are similar to previous changes (4)
  • test/main/scripts/afterPack.test.ts
  • test/main/presenter/pluginPresenter.test.ts
  • .github/workflows/release.yml
  • test/main/presenter/memoryVectorStore.test.ts

Comment thread scripts/smoke-duckdb-vss.js Outdated
Comment thread src/main/presenter/memoryPresenter/memoryVectorStore.ts
@yyhhyyyyyy
yyhhyyyyyy merged commit a124cd5 into dev Jun 28, 2026
3 checks passed
@zhangmo8
zhangmo8 deleted the fix/memory-first-turn-cold-start branch June 30, 2026 01:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant