Compare commits

...

2 Commits

Author SHA1 Message Date
582ad389e1 migrate LanceDB package and include pending UI updates 2026-03-16 00:33:48 +01:00
3283cc9ad5 Add new conversation button and session_id to AI chat
- Add "New conversation" button in home page header, next to SidebarTrigger,
  separated by a vertical divider (visible only after first message)
- Generate and persist session_id per chat context in useAIChat; reset to a
  new UUID on clearMessages so each new conversation gets a fresh session
- Floating chat auto-resets session_id on close (clearMessages already fires)
- Thread session_id through tRPC router → orchestrator → backend-client WS
  payloads (home_request and floating_request) as snake_cased session_id

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-16 00:32:54 +01:00
12 changed files with 279 additions and 334 deletions

View File

@@ -15,7 +15,7 @@ import { execSync } from 'node:child_process';
// Keep this list in sync with the Vite external array.
const externalPackages = [
'better-sqlite3',
'vectordb',
'@lancedb/lancedb',
'ws',
'electron-squirrel-startup',
'electron-store',
@@ -66,20 +66,20 @@ const config: ForgeConfig = {
const targetKey = `${platform}-${arch}`;
// vectordb uses platform-specific optional deps (@lancedb/vectordb-<platform>-<arch>-*).
// @lancedb/lancedb uses platform-specific optional deps (@lancedb/lancedb-<platform>-<arch>-*).
// npm install on Linux only pulls the Linux variant. Force-install the target's.
const platformNativePackages: Record<string, Record<string, string>> = {
'win32-x64': {
'@lancedb/vectordb-win32-x64-msvc': '',
'@lancedb/lancedb-win32-x64-msvc': '',
},
'linux-x64': {
'@lancedb/vectordb-linux-x64-gnu': '',
'@lancedb/lancedb-linux-x64-gnu': '',
},
'darwin-x64': {
'@lancedb/vectordb-darwin-x64': '',
'@lancedb/lancedb-darwin-x64': '',
},
'darwin-arm64': {
'@lancedb/vectordb-darwin-arm64': '',
'@lancedb/lancedb-darwin-arm64': '',
},
};
const nativePkgs = platformNativePackages[targetKey];
@@ -88,7 +88,7 @@ const config: ForgeConfig = {
const nmPath = path.join(buildPath, 'node_modules', '@lancedb');
if (fs.existsSync(nmPath)) {
for (const entry of fs.readdirSync(nmPath)) {
if (entry.startsWith('vectordb-') && !Object.keys(nativePkgs).includes(`@lancedb/${entry}`)) {
if (entry.startsWith('lancedb-') && !Object.keys(nativePkgs).includes(`@lancedb/${entry}`)) {
fs.rmSync(path.join(nmPath, entry), { recursive: true, force: true });
console.log(`[forge] Removed non-target native package: @lancedb/${entry}`);
}

495
package-lock.json generated
View File

@@ -11,6 +11,7 @@
"dependencies": {
"@fontsource/geist": "^5.2.8",
"@hello-pangea/dnd": "^18.0.1",
"@lancedb/lancedb": "^0.26.2",
"@milkdown/crepe": "^7.18.0",
"@tailwindcss/typography": "^0.5.19",
"@tailwindcss/vite": "^4.2.0",
@@ -40,7 +41,6 @@
"remark-gfm": "^4.0.1",
"tailwind-merge": "^3.5.0",
"tw-animate-css": "^1.4.0",
"vectordb": "^0.21.2",
"ws": "^8.19.0",
"zod": "^4.3.6"
},
@@ -76,30 +76,6 @@
"vite": "^5.4.21"
}
},
"node_modules/@75lb/deep-merge": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@75lb/deep-merge/-/deep-merge-1.1.2.tgz",
"integrity": "sha512-08K9ou5VNbheZFxM5tDWoqjA3ImC50DiuuJ2tj1yEPRfkp8lLLg6XAaJ4On+a0yAXor/8ay5gHnAIshRM44Kpw==",
"license": "MIT",
"peer": true,
"dependencies": {
"lodash": "^4.17.21",
"typical": "^7.1.1"
},
"engines": {
"node": ">=12.17"
}
},
"node_modules/@75lb/deep-merge/node_modules/typical": {
"version": "7.3.0",
"resolved": "https://registry.npmjs.org/typical/-/typical-7.3.0.tgz",
"integrity": "sha512-ya4mg/30vm+DOWfBg4YK3j2WD6TWtRkCbasOJr40CseYENzCUby/7rIvXA99JGsQHeNxLbnXdyLLxKSv3tauFw==",
"license": "MIT",
"peer": true,
"engines": {
"node": ">=12.17"
}
},
"node_modules/@antfu/ni": {
"version": "25.0.0",
"resolved": "https://registry.npmjs.org/@antfu/ni/-/ni-25.0.0.tgz",
@@ -122,39 +98,6 @@
"nup": "bin/nup.mjs"
}
},
"node_modules/@apache-arrow/ts": {
"version": "14.0.2",
"resolved": "https://registry.npmjs.org/@apache-arrow/ts/-/ts-14.0.2.tgz",
"integrity": "sha512-CtwAvLkK0CZv7xsYeCo91ml6PvlfzAmAJZkRYuz2GNBwfYufj5SVi0iuSMwIMkcU/szVwvLdzORSLa5PlF/2ug==",
"license": "Apache-2.0",
"peer": true,
"dependencies": {
"@types/command-line-args": "5.2.0",
"@types/command-line-usage": "5.0.2",
"@types/node": "20.3.0",
"@types/pad-left": "2.1.1",
"command-line-args": "5.2.1",
"command-line-usage": "7.0.1",
"flatbuffers": "23.5.26",
"json-bignum": "^0.0.3",
"pad-left": "^2.1.0",
"tslib": "^2.5.3"
}
},
"node_modules/@apache-arrow/ts/node_modules/@types/node": {
"version": "20.3.0",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.3.0.tgz",
"integrity": "sha512-cumHmIAf6On83X7yP+LrsEyUOf/YlociZelmpRYaGFydoaPdxdt80MAbu6vWerQT2COCp2nPvHdsbD7tHn/YlQ==",
"license": "MIT",
"peer": true
},
"node_modules/@apache-arrow/ts/node_modules/tslib": {
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
"license": "0BSD",
"peer": true
},
"node_modules/@babel/code-frame": {
"version": "7.29.0",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz",
@@ -3685,37 +3628,59 @@
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
"node_modules/@lancedb/vectordb-darwin-arm64": {
"version": "0.21.2",
"resolved": "https://registry.npmjs.org/@lancedb/vectordb-darwin-arm64/-/vectordb-darwin-arm64-0.21.2.tgz",
"integrity": "sha512-NAQnIKLw9K33KMODNXBEW0qC8/safWzZtqbVC7j1GcE7PSk0Uc6x7w5nrH5gvleZggjaxY9jaRVTqmtg7PNmqw==",
"node_modules/@lancedb/lancedb": {
"version": "0.26.2",
"resolved": "https://registry.npmjs.org/@lancedb/lancedb/-/lancedb-0.26.2.tgz",
"integrity": "sha512-umk4WMCTwJntLquwvUbpqE+TXREolcQVL9MHcxr8EhRjsha88+ATJ4QuS/hpyiE1CG3R/XcgrMgJAGkziPC/gA==",
"cpu": [
"x64",
"arm64"
],
"license": "Apache-2.0",
"os": [
"darwin",
"linux",
"win32"
],
"dependencies": {
"reflect-metadata": "^0.2.2"
},
"engines": {
"node": ">= 18"
},
"optionalDependencies": {
"@lancedb/lancedb-darwin-arm64": "0.26.2",
"@lancedb/lancedb-linux-arm64-gnu": "0.26.2",
"@lancedb/lancedb-linux-arm64-musl": "0.26.2",
"@lancedb/lancedb-linux-x64-gnu": "0.26.2",
"@lancedb/lancedb-linux-x64-musl": "0.26.2",
"@lancedb/lancedb-win32-arm64-msvc": "0.26.2",
"@lancedb/lancedb-win32-x64-msvc": "0.26.2"
},
"peerDependencies": {
"apache-arrow": ">=15.0.0 <=18.1.0"
}
},
"node_modules/@lancedb/lancedb-darwin-arm64": {
"version": "0.26.2",
"resolved": "https://registry.npmjs.org/@lancedb/lancedb-darwin-arm64/-/lancedb-darwin-arm64-0.26.2.tgz",
"integrity": "sha512-LAZ/v261eTlv44KoEm+AdqGnohS9IbVVVJkH9+8JTqwhe/k4j4Af8X9cD18tsaJAAtrGxxOCyIJ3wZTiBqrkCw==",
"cpu": [
"arm64"
],
"deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.",
"license": "Apache-2.0",
"optional": true,
"os": [
"darwin"
]
},
"node_modules/@lancedb/vectordb-darwin-x64": {
"version": "0.21.2",
"resolved": "https://registry.npmjs.org/@lancedb/vectordb-darwin-x64/-/vectordb-darwin-x64-0.21.2.tgz",
"integrity": "sha512-PudbltlbRiXvBf/bkAaDPL8+RqcI4TG69u00rQHxwkhH7PgPYRTUjfzfaQfiDXZuLXuZHQq703RyoHOqzsHN0Q==",
"cpu": [
"x64"
],
"license": "Apache-2.0",
"optional": true,
"os": [
"darwin"
]
"engines": {
"node": ">= 18"
}
},
"node_modules/@lancedb/vectordb-linux-arm64-gnu": {
"version": "0.21.2",
"resolved": "https://registry.npmjs.org/@lancedb/vectordb-linux-arm64-gnu/-/vectordb-linux-arm64-gnu-0.21.2.tgz",
"integrity": "sha512-3lJ8lootlwLmhqabCdg0DKftv0Ujep6NTWAoLWK/6VQe2IgHmu/ZPRNQkOSZ5tnYlmRyDiMDMB2tlAzo45sV8Q==",
"node_modules/@lancedb/lancedb-linux-arm64-gnu": {
"version": "0.26.2",
"resolved": "https://registry.npmjs.org/@lancedb/lancedb-linux-arm64-gnu/-/lancedb-linux-arm64-gnu-0.26.2.tgz",
"integrity": "sha512-guHKm+zvuQB22dgyn6/sYZJvD6IL9lC24cl6ZuzVX/jYgag/gNLHT86HongrcBjgdjI6+YIGmdfD6b/iAKxn3Q==",
"cpu": [
"arm64"
],
@@ -3723,12 +3688,31 @@
"optional": true,
"os": [
"linux"
]
],
"engines": {
"node": ">= 18"
}
},
"node_modules/@lancedb/vectordb-linux-x64-gnu": {
"version": "0.21.2",
"resolved": "https://registry.npmjs.org/@lancedb/vectordb-linux-x64-gnu/-/vectordb-linux-x64-gnu-0.21.2.tgz",
"integrity": "sha512-5I2drMOIyRODlAHPsipQBTrRRgcOZ45N5GsuhqcKnz3Tg8GAdc1MQKyK3BrdJzKHLPdRtIyRJ6QTLB3wZvDsQQ==",
"node_modules/@lancedb/lancedb-linux-arm64-musl": {
"version": "0.26.2",
"resolved": "https://registry.npmjs.org/@lancedb/lancedb-linux-arm64-musl/-/lancedb-linux-arm64-musl-0.26.2.tgz",
"integrity": "sha512-pR6Hs/0iphItrJYYLf/yrqCC+scPcHpCGl6rHqcU2GHxo5RFpzlMzqW1DiXScGiBRuCcD9HIMec+kBsOgXv4GQ==",
"cpu": [
"arm64"
],
"license": "Apache-2.0",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 18"
}
},
"node_modules/@lancedb/lancedb-linux-x64-gnu": {
"version": "0.26.2",
"resolved": "https://registry.npmjs.org/@lancedb/lancedb-linux-x64-gnu/-/lancedb-linux-x64-gnu-0.26.2.tgz",
"integrity": "sha512-u4UUSPwd2YecgGqWjh9W0MHKgsVwB2Ch2ROpF8AY+IA7kpGsbB18R1/t7v2B0q7pahRy20dgsaku5LH1zuzMRQ==",
"cpu": [
"x64"
],
@@ -3736,12 +3720,47 @@
"optional": true,
"os": [
"linux"
]
],
"engines": {
"node": ">= 18"
}
},
"node_modules/@lancedb/vectordb-win32-x64-msvc": {
"version": "0.21.2",
"resolved": "https://registry.npmjs.org/@lancedb/vectordb-win32-x64-msvc/-/vectordb-win32-x64-msvc-0.21.2.tgz",
"integrity": "sha512-gjpFukq0NTQSRpWPNIpq4XFtaudjSNBT6DMsagC61D2nx9ZLEdSAdU0wdkeluQwhoMvNnXEPdP9HxDSFUXk+Ww==",
"node_modules/@lancedb/lancedb-linux-x64-musl": {
"version": "0.26.2",
"resolved": "https://registry.npmjs.org/@lancedb/lancedb-linux-x64-musl/-/lancedb-linux-x64-musl-0.26.2.tgz",
"integrity": "sha512-XIS4qkVfGlzmsUPqAG2iKt8ykuz28GfemGC0ijXwu04kC1pYiCFzTpB3UIZjm5oM7OTync1aQ3mGTj1oCciSPA==",
"cpu": [
"x64"
],
"license": "Apache-2.0",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 18"
}
},
"node_modules/@lancedb/lancedb-win32-arm64-msvc": {
"version": "0.26.2",
"resolved": "https://registry.npmjs.org/@lancedb/lancedb-win32-arm64-msvc/-/lancedb-win32-arm64-msvc-0.26.2.tgz",
"integrity": "sha512-//tZDPitm2PxNvalHP+m+Pf6VvFAeQgcht1+HJnutjH4gp6xYW6ynQlWWFDBmz9WRkUT+mXu2O4FUIhbdNaJSQ==",
"cpu": [
"arm64"
],
"license": "Apache-2.0",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">= 18"
}
},
"node_modules/@lancedb/lancedb-win32-x64-msvc": {
"version": "0.26.2",
"resolved": "https://registry.npmjs.org/@lancedb/lancedb-win32-x64-msvc/-/lancedb-win32-x64-msvc-0.26.2.tgz",
"integrity": "sha512-GH3pfyzicgPGTb84xMXgujlWDaAnBTmUyjooYiCE2tC24BaehX4hgFhXivamzAEsF5U2eVsA/J60Ppif+skAbA==",
"cpu": [
"x64"
],
@@ -3749,7 +3768,10 @@
"optional": true,
"os": [
"win32"
]
],
"engines": {
"node": ">= 18"
}
},
"node_modules/@lezer/common": {
"version": "1.5.1",
@@ -4645,12 +4667,6 @@
"@tybys/wasm-util": "^0.10.0"
}
},
"node_modules/@neon-rs/load": {
"version": "0.0.74",
"resolved": "https://registry.npmjs.org/@neon-rs/load/-/load-0.0.74.tgz",
"integrity": "sha512-/cPZD907UNz55yrc/ud4wDgQKtU1TvkD9jeqZWG6J4IMmZkp6zgjkQcKA8UvpkZlcpPHvc8J17sGzLFbP/LUYg==",
"license": "MIT"
},
"node_modules/@noble/ciphers": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-1.3.0.tgz",
@@ -7182,6 +7198,23 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/@swc/helpers": {
"version": "0.5.19",
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.19.tgz",
"integrity": "sha512-QamiFeIK3txNjgUTNppE6MiG3p7TdninpZu0E0PbqVh1a9FNLT2FRhisaa4NcaX52XVhA5l7Pk58Ft7Sqi/2sA==",
"license": "Apache-2.0",
"peer": true,
"dependencies": {
"tslib": "^2.8.0"
}
},
"node_modules/@swc/helpers/node_modules/tslib": {
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
"license": "0BSD",
"peer": true
},
"node_modules/@szmarczak/http-timer": {
"version": "4.0.6",
"resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz",
@@ -7929,16 +7962,16 @@
}
},
"node_modules/@types/command-line-args": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/@types/command-line-args/-/command-line-args-5.2.0.tgz",
"integrity": "sha512-UuKzKpJJ/Ief6ufIaIzr3A/0XnluX7RvFgwkV89Yzvm77wCh1kFaFmqN8XEnGcN62EuHdedQjEMb8mYxFLGPyA==",
"version": "5.2.3",
"resolved": "https://registry.npmjs.org/@types/command-line-args/-/command-line-args-5.2.3.tgz",
"integrity": "sha512-uv0aG6R0Y8WHZLTamZwtfsDLVRnOa+n+n5rEvFWL5Na5gZ8V2Teab/duDPFzIIIhs9qizDpcavCusCLJZu62Kw==",
"license": "MIT",
"peer": true
},
"node_modules/@types/command-line-usage": {
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/@types/command-line-usage/-/command-line-usage-5.0.2.tgz",
"integrity": "sha512-n7RlEEJ+4x4TS7ZQddTmNSxP+zziEG0TNsMfiRIxcIVXt71ENJ9ojeXmGO3wPoTdn7pJcU2xc3CJYMktNT6DPg==",
"version": "5.0.4",
"resolved": "https://registry.npmjs.org/@types/command-line-usage/-/command-line-usage-5.0.4.tgz",
"integrity": "sha512-BwR5KP3Es/CSht0xqBcUXS3qCAUVXwpRKsV2+arxeb65atasuXG9LykC9Ab10Cw3s2raH92ZqOeILaQbsB2ACg==",
"license": "MIT",
"peer": true
},
@@ -8164,13 +8197,6 @@
"undici-types": "~7.18.0"
}
},
"node_modules/@types/pad-left": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/@types/pad-left/-/pad-left-2.1.1.tgz",
"integrity": "sha512-Xd22WCRBydkGSApl5Bw0PhAOHKSVjNL3E3AwzKaps96IMraPqy5BvZIsBVK6JLwdybUzjHnuWVwpDd0JjTfHXA==",
"license": "MIT",
"peer": true
},
"node_modules/@types/react": {
"version": "19.2.14",
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz",
@@ -9319,33 +9345,35 @@
}
},
"node_modules/apache-arrow": {
"version": "14.0.2",
"resolved": "https://registry.npmjs.org/apache-arrow/-/apache-arrow-14.0.2.tgz",
"integrity": "sha512-EBO2xJN36/XoY81nhLcwCJgFwkboDZeyNQ+OPsG7bCoQjc2BT0aTyH/MR6SrL+LirSNz+cYqjGRlupMMlP1aEg==",
"version": "18.1.0",
"resolved": "https://registry.npmjs.org/apache-arrow/-/apache-arrow-18.1.0.tgz",
"integrity": "sha512-v/ShMp57iBnBp4lDgV8Jx3d3Q5/Hac25FWmQ98eMahUiHPXcvwIMKJD0hBIgclm/FCG+LwPkAKtkRO1O/W0YGg==",
"license": "Apache-2.0",
"peer": true,
"dependencies": {
"@types/command-line-args": "5.2.0",
"@types/command-line-usage": "5.0.2",
"@types/node": "20.3.0",
"@types/pad-left": "2.1.1",
"command-line-args": "5.2.1",
"command-line-usage": "7.0.1",
"flatbuffers": "23.5.26",
"@swc/helpers": "^0.5.11",
"@types/command-line-args": "^5.2.3",
"@types/command-line-usage": "^5.0.4",
"@types/node": "^20.13.0",
"command-line-args": "^5.2.1",
"command-line-usage": "^7.0.1",
"flatbuffers": "^24.3.25",
"json-bignum": "^0.0.3",
"pad-left": "^2.1.0",
"tslib": "^2.5.3"
"tslib": "^2.6.2"
},
"bin": {
"arrow2csv": "bin/arrow2csv.js"
}
},
"node_modules/apache-arrow/node_modules/@types/node": {
"version": "20.3.0",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.3.0.tgz",
"integrity": "sha512-cumHmIAf6On83X7yP+LrsEyUOf/YlociZelmpRYaGFydoaPdxdt80MAbu6vWerQT2COCp2nPvHdsbD7tHn/YlQ==",
"version": "20.19.37",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.37.tgz",
"integrity": "sha512-8kzdPJ3FsNsVIurqBs7oodNnCEVbni9yUEkaHbgptDACOPW04jimGagZ51E6+lXUwJjgnBw+hyko/lkFWCldqw==",
"license": "MIT",
"peer": true
"peer": true,
"dependencies": {
"undici-types": "~6.21.0"
}
},
"node_modules/apache-arrow/node_modules/tslib": {
"version": "2.8.1",
@@ -9354,6 +9382,13 @@
"license": "0BSD",
"peer": true
},
"node_modules/apache-arrow/node_modules/undici-types": {
"version": "6.21.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
"integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
"license": "MIT",
"peer": true
},
"node_modules/argparse": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
@@ -9551,12 +9586,6 @@
"node": ">= 0.4"
}
},
"node_modules/asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
"license": "MIT"
},
"node_modules/at-least-node": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz",
@@ -9602,17 +9631,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/axios": {
"version": "1.13.5",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.13.5.tgz",
"integrity": "sha512-cz4ur7Vb0xS4/KUN0tPWe44eqxrIu31me+fbang3ijiNscE129POzipJJA6zniq2C/Z6sJCjMimjS8Lc/GAs8Q==",
"license": "MIT",
"dependencies": {
"follow-redirects": "^1.15.11",
"form-data": "^4.0.5",
"proxy-from-env": "^1.1.0"
}
},
"node_modules/babel-dead-code-elimination": {
"version": "1.0.12",
"resolved": "https://registry.npmjs.org/babel-dead-code-elimination/-/babel-dead-code-elimination-1.0.12.tgz",
@@ -10032,6 +10050,7 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
"integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
@@ -10458,18 +10477,6 @@
"dev": true,
"license": "MIT"
},
"node_modules/combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"license": "MIT",
"dependencies": {
"delayed-stream": "~1.0.0"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/comma-separated-tokens": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz",
@@ -10497,16 +10504,16 @@
}
},
"node_modules/command-line-usage": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-7.0.1.tgz",
"integrity": "sha512-NCyznE//MuTjwi3y84QVUGEOT+P5oto1e1Pk/jFPVdPPfsG03qpTIl3yw6etR+v73d0lXsoojRpvbru2sqePxQ==",
"version": "7.0.4",
"resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-7.0.4.tgz",
"integrity": "sha512-85UdvzTNx/+s5CkSgBm/0hzP80RFHAa7PsfeADE5ezZF3uHz3/Tqj9gIKGT9PTtpycc3Ua64T0oVulGfKxzfqg==",
"license": "MIT",
"peer": true,
"dependencies": {
"array-back": "^6.2.2",
"chalk-template": "^0.4.0",
"table-layout": "^3.0.0",
"typical": "^7.1.1"
"table-layout": "^4.1.1",
"typical": "^7.3.0"
},
"engines": {
"node": ">=12.20.0"
@@ -11242,15 +11249,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
"license": "MIT",
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/depd": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
@@ -12044,6 +12042,7 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
"integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.1",
@@ -12868,6 +12867,7 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
@@ -12877,6 +12877,7 @@
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
@@ -12893,6 +12894,7 @@
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
"dev": true,
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0"
@@ -12905,6 +12907,7 @@
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
"dev": true,
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
@@ -14050,10 +14053,10 @@
}
},
"node_modules/flatbuffers": {
"version": "23.5.26",
"resolved": "https://registry.npmjs.org/flatbuffers/-/flatbuffers-23.5.26.tgz",
"integrity": "sha512-vE+SI9vrJDwi1oETtTIFldC/o9GsVKRM+s6EL0nQgxXlYV1Vc4Tk30hj4xGICftInKQKj1F3up2n8UbIVobISQ==",
"license": "SEE LICENSE IN LICENSE",
"version": "24.12.23",
"resolved": "https://registry.npmjs.org/flatbuffers/-/flatbuffers-24.12.23.tgz",
"integrity": "sha512-dLVCAISd5mhls514keQzmEG6QHmUUsNuWsb4tFafIUwvvgDjXhtfAYSKOzt5SWOy+qByV5pbsDZ+Vb7HUOBEdA==",
"license": "Apache-2.0",
"peer": true
},
"node_modules/flatted": {
@@ -14077,26 +14080,6 @@
"node": ">= 12"
}
},
"node_modules/follow-redirects": {
"version": "1.15.11",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz",
"integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==",
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/RubenVerborgh"
}
],
"license": "MIT",
"engines": {
"node": ">=4.0"
},
"peerDependenciesMeta": {
"debug": {
"optional": true
}
}
},
"node_modules/for-each": {
"version": "0.3.5",
"resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz",
@@ -14113,22 +14096,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/form-data": {
"version": "4.0.5",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz",
"integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==",
"license": "MIT",
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"es-set-tostringtag": "^2.1.0",
"hasown": "^2.0.2",
"mime-types": "^2.1.12"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/formatly": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/formatly/-/formatly-0.3.0.tgz",
@@ -14270,6 +14237,7 @@
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
"dev": true,
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/ljharb"
@@ -14406,6 +14374,7 @@
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
"integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.2",
@@ -14485,6 +14454,7 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
"integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
"dev": true,
"license": "MIT",
"dependencies": {
"dunder-proto": "^1.0.1",
@@ -14682,6 +14652,7 @@
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
@@ -14794,6 +14765,7 @@
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
"integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
@@ -14806,6 +14778,7 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
"dev": true,
"license": "MIT",
"dependencies": {
"has-symbols": "^1.0.3"
@@ -14821,6 +14794,7 @@
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"function-bind": "^1.1.2"
@@ -16820,6 +16794,7 @@
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
"integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
@@ -17796,6 +17771,7 @@
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.6"
@@ -17805,6 +17781,7 @@
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"dev": true,
"license": "MIT",
"dependencies": {
"mime-db": "1.52.0"
@@ -18888,19 +18865,6 @@
"dev": true,
"license": "MIT"
},
"node_modules/pad-left": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/pad-left/-/pad-left-2.1.0.tgz",
"integrity": "sha512-HJxs9K9AztdIQIAIa/OIazRAUW/L6B9hbQDxO4X07roW3eo9XqZc2ur9bn1StH9CnbbI9EgvejHQX7CBpCF1QA==",
"license": "MIT",
"peer": true,
"dependencies": {
"repeat-string": "^1.5.4"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/pako": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
@@ -19713,12 +19677,6 @@
"node": ">= 0.10"
}
},
"node_modules/proxy-from-env": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
"license": "MIT"
},
"node_modules/pump": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz",
@@ -20471,6 +20429,12 @@
"integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==",
"license": "MIT"
},
"node_modules/reflect-metadata": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz",
"integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==",
"license": "Apache-2.0"
},
"node_modules/reflect.getprototypeof": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz",
@@ -20628,16 +20592,6 @@
"url": "https://opencollective.com/unified"
}
},
"node_modules/repeat-string": {
"version": "1.6.1",
"resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
"integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==",
"license": "MIT",
"peer": true,
"engines": {
"node": ">=0.10"
}
},
"node_modules/require-directory": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
@@ -22184,16 +22138,6 @@
"node": ">= 0.4"
}
},
"node_modules/stream-read-all": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/stream-read-all/-/stream-read-all-3.0.1.tgz",
"integrity": "sha512-EWZT9XOceBPlVJRrYcykW8jyRSZYbkb/0ZK36uLEmoWVO5gxBOnntNTseNzfREsqxqdfEGQrD8SXQ3QWbBmq8A==",
"license": "MIT",
"peer": true,
"engines": {
"node": ">=10"
}
},
"node_modules/strict-event-emitter": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/strict-event-emitter/-/strict-event-emitter-0.5.1.tgz",
@@ -22503,23 +22447,15 @@
}
},
"node_modules/table-layout": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/table-layout/-/table-layout-3.0.2.tgz",
"integrity": "sha512-rpyNZYRw+/C+dYkcQ3Pr+rLxW4CfHpXjPDnG7lYhdRoUcZTUt+KEsX+94RGp/aVp/MQU35JCITv2T/beY4m+hw==",
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/table-layout/-/table-layout-4.1.1.tgz",
"integrity": "sha512-iK5/YhZxq5GO5z8wb0bY1317uDF3Zjpha0QFFLA8/trAoiLbQD0HUbMesEaxyzUgDxi2QlcbM8IvqOlEjgoXBA==",
"license": "MIT",
"peer": true,
"dependencies": {
"@75lb/deep-merge": "^1.1.1",
"array-back": "^6.2.2",
"command-line-args": "^5.2.1",
"command-line-usage": "^7.0.0",
"stream-read-all": "^3.0.1",
"typical": "^7.1.1",
"wordwrapjs": "^5.1.0"
},
"bin": {
"table-layout": "bin/cli.js"
},
"engines": {
"node": ">=12.17"
}
@@ -22534,16 +22470,6 @@
"node": ">=12.17"
}
},
"node_modules/table-layout/node_modules/typical": {
"version": "7.3.0",
"resolved": "https://registry.npmjs.org/typical/-/typical-7.3.0.tgz",
"integrity": "sha512-ya4mg/30vm+DOWfBg4YK3j2WD6TWtRkCbasOJr40CseYENzCUby/7rIvXA99JGsQHeNxLbnXdyLLxKSv3tauFw==",
"license": "MIT",
"peer": true,
"engines": {
"node": ">=12.17"
}
},
"node_modules/tagged-tag": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/tagged-tag/-/tagged-tag-1.0.0.tgz",
@@ -24091,37 +24017,6 @@
"node": ">= 0.8"
}
},
"node_modules/vectordb": {
"version": "0.21.2",
"resolved": "https://registry.npmjs.org/vectordb/-/vectordb-0.21.2.tgz",
"integrity": "sha512-5tiwUq0jDtfIpcr7NY+kNCTecHCzSq0AqQtMzJphH7z6H6gfrw9t5/Aoy5/QnS0uAWIgqvCbE5qneQOFGxE+Og==",
"cpu": [
"x64",
"arm64"
],
"deprecated": "Use @lancedb/lancedb instead.",
"license": "Apache-2.0",
"os": [
"darwin",
"linux",
"win32"
],
"dependencies": {
"@neon-rs/load": "^0.0.74",
"axios": "^1.4.0"
},
"optionalDependencies": {
"@lancedb/vectordb-darwin-arm64": "0.21.2",
"@lancedb/vectordb-darwin-x64": "0.21.2",
"@lancedb/vectordb-linux-arm64-gnu": "0.21.2",
"@lancedb/vectordb-linux-x64-gnu": "0.21.2",
"@lancedb/vectordb-win32-x64-msvc": "0.21.2"
},
"peerDependencies": {
"@apache-arrow/ts": "^14.0.2",
"apache-arrow": "^14.0.2"
}
},
"node_modules/vfile": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz",

View File

@@ -50,6 +50,7 @@
"dependencies": {
"@fontsource/geist": "^5.2.8",
"@hello-pangea/dnd": "^18.0.1",
"@lancedb/lancedb": "^0.26.2",
"@milkdown/crepe": "^7.18.0",
"@tailwindcss/typography": "^0.5.19",
"@tailwindcss/vite": "^4.2.0",
@@ -79,7 +80,6 @@
"remark-gfm": "^4.0.1",
"tailwind-merge": "^3.5.0",
"tw-animate-css": "^1.4.0",
"vectordb": "^0.21.2",
"ws": "^8.19.0",
"zod": "^4.3.6"
}

View File

@@ -32,6 +32,7 @@ const NOOP = () => undefined;
interface OrchestrateInput {
message: string;
requestId?: string;
sessionId?: string;
conversationHistory?: Array<{ role: 'user' | 'assistant' | 'system'; content: string }>;
sender?: Electron.WebContents;
}
@@ -39,6 +40,7 @@ interface OrchestrateInput {
interface OrchestrateFloatingInput {
message: string;
requestId?: string;
sessionId?: string;
scope: WsFloatingRequest['scope'];
sender?: Electron.WebContents;
}
@@ -83,14 +85,14 @@ async function checkConnectivity(): Promise<{ ok: true } | { ok: false; error: s
// ---------------------------------------------------------------------------
export async function orchestrate(input: OrchestrateInput): Promise<OrchestrateResult> {
const { message, requestId, conversationHistory, sender } = input;
const { message, requestId, sessionId, conversationHistory, sender } = input;
const check = await checkConnectivity();
if (!check.ok) return { response: '', error: check.error };
try {
const client = getBackendClient();
const { requestId: activeRequestId, promise } = client.sendHomeRequest(message, conversationHistory, requestId, {
const { requestId: activeRequestId, promise } = client.sendHomeRequest(message, conversationHistory, requestId, sessionId, {
onStart: () => sendFrame(sender, { type: 'stream_start', requestId: activeRequestId }),
onText: (chunk) => sendFrame(sender, { type: 'stream_text', requestId: activeRequestId, chunk }),
onEnd: (mutations) => sendFrame(sender, { type: 'stream_end', requestId: activeRequestId, mutations: mutations as unknown[] | undefined }),
@@ -119,14 +121,14 @@ export async function orchestrate(input: OrchestrateInput): Promise<OrchestrateR
// ---------------------------------------------------------------------------
export async function orchestrateFloating(input: OrchestrateFloatingInput): Promise<OrchestrateResult> {
const { message, requestId, scope, sender } = input;
const { message, requestId, sessionId, scope, sender } = input;
const check = await checkConnectivity();
if (!check.ok) return { response: '', error: check.error };
try {
const client = getBackendClient();
const { requestId: activeRequestId, promise } = client.sendFloatingRequest(message, scope, requestId, {
const { requestId: activeRequestId, promise } = client.sendFloatingRequest(message, scope, requestId, sessionId, {
onStart: () => sendFrame(sender, { type: 'stream_start', requestId: activeRequestId }),
onText: (chunk) => sendFrame(sender, { type: 'stream_text', requestId: activeRequestId, chunk }),
onEnd: (mutations) => sendFrame(sender, { type: 'stream_end', requestId: activeRequestId, mutations: mutations as unknown[] | undefined }),

View File

@@ -235,6 +235,7 @@ export class BackendClient {
message: string,
conversationHistory?: Array<{ role: 'user' | 'assistant' | 'system'; content: string }>,
requestId?: string,
sessionId?: string,
callbacks?: Partial<Omit<StreamListener, 'resolve' | 'reject'>>,
): { requestId: string; promise: Promise<void> } {
const activeRequestId = requestId ?? crypto.randomUUID();
@@ -264,7 +265,7 @@ export class BackendClient {
return;
}
const homePayload = toSnakeCase({ type: 'home_request', requestId: activeRequestId, message, conversationHistory });
const homePayload = toSnakeCase({ type: 'home_request', requestId: activeRequestId, sessionId, message, conversationHistory });
logWsSend(homePayload);
ws.send(JSON.stringify(homePayload));
});
@@ -280,6 +281,7 @@ export class BackendClient {
message: string,
scope: WsFloatingRequest['scope'],
requestId?: string,
sessionId?: string,
callbacks?: Partial<Omit<StreamListener, 'resolve' | 'reject'>>,
): { requestId: string; promise: Promise<void> } {
const activeRequestId = requestId ?? crypto.randomUUID();
@@ -309,7 +311,7 @@ export class BackendClient {
return;
}
const floatingPayload = toSnakeCase({ type: 'floating_request', requestId: activeRequestId, message, scope });
const floatingPayload = toSnakeCase({ type: 'floating_request', requestId: activeRequestId, sessionId, message, scope });
logWsSend(floatingPayload);
ws.send(JSON.stringify(floatingPayload));
});

View File

@@ -1,4 +1,4 @@
import * as lancedb from 'vectordb';
import * as lancedb from '@lancedb/lancedb';
import { app } from 'electron';
import path from 'node:path';
import { getDb } from './index';

View File

@@ -655,6 +655,7 @@ const aiRouter = router({
role: z.enum(['user', 'assistant', 'system']),
content: z.string(),
})).optional(),
sessionId: z.string().optional(),
mode: z.enum(['home', 'floating']).optional(),
scope: z.object({
type: z.enum(['task', 'project', 'note', 'timeline']),
@@ -667,6 +668,7 @@ const aiRouter = router({
return await orchestrateFloating({
message: input.message,
requestId: input.requestId,
sessionId: input.sessionId,
scope: input.scope,
sender: ctx.sender,
});
@@ -674,6 +676,7 @@ const aiRouter = router({
return await orchestrate({
message: input.message,
requestId: input.requestId,
sessionId: input.sessionId,
conversationHistory: input.conversationHistory,
sender: ctx.sender,
});

View File

@@ -197,10 +197,14 @@ let aiMinHeightCache: number | null = null;
interface AIChatPanelProps {
isHomePage?: boolean;
actionsRef?: React.MutableRefObject<{ clear: () => void } | null>;
onHasMessagesChange?: (has: boolean) => void;
}
export function AIChatPanel({
isHomePage,
actionsRef,
onHasMessagesChange,
}: AIChatPanelProps) {
const utils = trpc.useUtils();
const authStatusQuery = trpc.auth.status.useQuery();
@@ -220,9 +224,15 @@ export function AIChatPanel({
isStreaming,
streamingContent,
handleSend: chatHandleSend,
clearMessages,
} = useAIChat(chatContext);
const hasMessages = messages.length > 0 || isStreaming;
// Notify parent when conversation active state changes
useEffect(() => {
onHasMessagesChange?.(hasMessages);
}, [hasMessages, onHasMessagesChange]);
// Daily brief state — initialized from module-level cache so remounts are instant.
const [dailyBrief, setDailyBrief] = useState<string | null>(() => briefModule.content);
const briefContentRef = useRef('');
@@ -239,17 +249,28 @@ export function AIChatPanel({
const [aiMinHeight, setAiMinHeight] = useState<number | null>(
() => aiMinHeightCache,
);
// Expose clear action to parent (AppShell) via ref — placed after setAiMinHeight is in scope
if (actionsRef) {
actionsRef.current = {
clear: () => {
clearMessages();
aiMinHeightCache = null;
setAiMinHeight(null);
},
};
}
const pendingScrollRef = useRef(false);
// Stable layout values — recomputed only on mount and window resize.
const stableLayout = useRef({ aiMessagePadding: 0, messageGap: 0 });
const stableLayout = useRef({ messageGap: 0 });
useEffect(() => {
function measureStable() {
const rootStyles = window.getComputedStyle(document.documentElement);
const spacingNumber = parseFloat(rootStyles.getPropertyValue('--spacing').trim()) || 0;
const rootFontSize = parseFloat(rootStyles.fontSize) || 16;
stableLayout.current = {
aiMessagePadding: spacingNumber * 40 * rootFontSize,
messageGap: spacingNumber * 8 * rootFontSize,
};
}
@@ -277,16 +298,13 @@ export function AIChatPanel({
pendingScrollRef.current = false;
const { aiMessagePadding, messageGap } = stableLayout.current;
const { messageGap } = stableLayout.current;
const vhw = window.innerHeight;
const briefHeight = briefWrapper.current?.getBoundingClientRect().height || 0;
const userMsgHeight = lastUserMsgRef.current?.getBoundingClientRect().height || 0;
const chatInputHeight = chatInputWrapperRef.current?.getBoundingClientRect().height || 0;
const minH = Math.max(0, Math.round(vhw - (briefHeight + userMsgHeight + messageGap)));
console.log('Computed AI minHeight:', { vhw, aiMessagePadding, briefHeight, userMsgHeight, chatInputHeight, messageGap, minH });
aiMinHeightCache = minH;
setAiMinHeight(minH);

View File

@@ -1,4 +1,4 @@
import { useState } from 'react';
import { useState, useRef } from 'react';
import { Link, useRouterState } from '@tanstack/react-router';
import { LayoutGroup } from 'framer-motion';
import {
@@ -12,6 +12,7 @@ import {
Moon,
Monitor,
ChevronsUpDown,
SquarePen,
} from 'lucide-react';
import { trpc } from '@/lib/trpc';
import { useDoubleClickAI } from '@/hooks/useDoubleClickAI';
@@ -97,6 +98,9 @@ function AppShellInner({ children }: AppShellProps) {
setSidebarCollapsedMutation.mutate({ collapsed: !value });
};
const chatActionsRef = useRef<{ clear: () => void } | null>(null);
const [homeChatHasMessages, setHomeChatHasMessages] = useState(false);
const isHomePage = currentPath === '/';
const isProjectsPage = currentPath.startsWith('/projects');
const isNotesPage = currentPath.startsWith('/notes');
@@ -144,8 +148,22 @@ function AppShellInner({ children }: AppShellProps) {
)}
{isHomePage ? (
<div className="relative flex-1 min-h-0">
<SidebarTrigger className="absolute top-3 left-3 z-10" />
<AIChatPanel isHomePage />
<div className="absolute top-3 left-3 z-10 flex items-center gap-1">
<SidebarTrigger />
{homeChatHasMessages && (
<>
<Separator orientation="vertical" className="data-[orientation=vertical]:h-4 data-[orientation=vertical]:w-px mx-1" />
<button
onClick={() => chatActionsRef.current?.clear()}
aria-label="New conversation"
className="flex h-7 w-7 items-center justify-center rounded-md text-muted-foreground transition-colors hover:text-foreground hover:bg-accent"
>
<SquarePen size={16} />
</button>
</>
)}
</div>
<AIChatPanel isHomePage actionsRef={chatActionsRef} onHasMessagesChange={setHomeChatHasMessages} />
</div>
) : (
children

View File

@@ -54,6 +54,7 @@ interface UseAIChatOptions {
interface CachedChatState {
messages: ChatMessage[];
input: string;
sessionId: string;
}
const chatSessionCache = new Map<string, CachedChatState>();
@@ -114,6 +115,9 @@ export function useAIChat(defaultContext: UIChatContext, options?: UseAIChatOpti
const [input, setInput] = useState(
() => chatSessionCache.get(contextCacheKey)?.input ?? '',
);
const [sessionId, setSessionId] = useState<string>(
() => chatSessionCache.get(contextCacheKey)?.sessionId ?? crypto.randomUUID(),
);
const [isStreaming, setIsStreaming] = useState(false);
const [streamingContent, setStreamingContent] = useState('');
@@ -125,6 +129,7 @@ export function useAIChat(defaultContext: UIChatContext, options?: UseAIChatOpti
const cached = chatSessionCache.get(contextCacheKey);
setMessages(cached?.messages ?? []);
setInput(cached?.input ?? '');
setSessionId(cached?.sessionId ?? crypto.randomUUID());
setIsStreaming(false);
setStreamingContent('');
streamingContentRef.current = '';
@@ -132,15 +137,17 @@ export function useAIChat(defaultContext: UIChatContext, options?: UseAIChatOpti
// Persist the chat session so remounting the panel restores the conversation.
useEffect(() => {
chatSessionCache.set(contextCacheKey, { messages, input });
}, [contextCacheKey, messages, input]);
chatSessionCache.set(contextCacheKey, { messages, input, sessionId });
}, [contextCacheKey, messages, input, sessionId]);
const clearMessages = useCallback(() => {
const newSessionId = crypto.randomUUID();
setMessages([]);
setStreamingContent('');
streamingContentRef.current = '';
chatSessionCache.set(contextCacheKey, { messages: [], input: '' });
setInput('');
setSessionId(newSessionId);
chatSessionCache.set(contextCacheKey, { messages: [], input: '', sessionId: newSessionId });
}, [contextCacheKey]);
const handleSend = useCallback(
@@ -216,6 +223,7 @@ export function useAIChat(defaultContext: UIChatContext, options?: UseAIChatOpti
requestId,
message: trimmed,
conversationHistory,
sessionId,
...(isFloating && ctx.scope
? { mode: 'floating' as const, scope: ctx.scope }
: {}),
@@ -271,7 +279,7 @@ export function useAIChat(defaultContext: UIChatContext, options?: UseAIChatOpti
},
);
},
[input, isStreaming, defaultContext, chatMutation, messages, options],
[input, isStreaming, defaultContext, chatMutation, messages, options, sessionId],
);
return {

View File

@@ -147,15 +147,14 @@ function TimelinePage() {
</div>
<div className="flex items-center gap-3">
<div className="flex items-center gap-1.5">
<Label htmlFor="show-archived" className="text-xs text-muted-foreground">
Show Archived
</Label>
<Switch
id="show-archived"
checked={showArchived}
onCheckedChange={setShowArchived}
/>
<Label htmlFor="show-archived" className="text-xs text-muted-foreground">
<Archive className="h-3 w-3 inline mr-0.5" />
Archived
</Label>
</div>
<Button size="sm" onClick={() => setDialogOpen(true)}>
<Plus className="h-4 w-4 mr-1" />

View File

@@ -14,7 +14,7 @@ export default defineConfig({
external: [
'better-sqlite3',
'ws',
'vectordb',
'@lancedb/lancedb',
],
output: {
entryFileNames: 'main.js',