From 75bd1b0266514ea674b14bdd759397ab22c080c8 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sat, 27 Jun 2026 08:42:28 +0000
Subject: [PATCH 1/5] feat: add embeddings endpoint setting
---
bun.lock | 74 +++++++---------
.../settings/EmbeddingsKeySection.tsx | 6 +-
.../settings/SearchSection.dom.test.tsx | 87 ++++++++++++++++---
.../src/components/settings/SearchSection.tsx | 72 ++++++++++++++-
packages/cli/src/commands/embeddings/index.ts | 14 +--
5 files changed, 188 insertions(+), 65 deletions(-)
diff --git a/bun.lock b/bun.lock
index 64012d74..46e5b191 100644
--- a/bun.lock
+++ b/bun.lock
@@ -1774,7 +1774,7 @@
"@types/ms": ["@types/ms@2.1.0", "", {}, "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA=="],
- "@types/node": ["@types/node@25.6.0", "", { "dependencies": { "undici-types": "~7.19.0" } }, "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ=="],
+ "@types/node": ["@types/node@24.12.2", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-A1sre26ke7HDIuY/M23nd9gfB+nrmhtYyMINbjI1zHJxYteKR6qSMX56FsmjMcDb3SMcjJg5BiRRgOCC/yBD0g=="],
"@types/node-fetch": ["@types/node-fetch@2.6.13", "", { "dependencies": { "@types/node": "*", "form-data": "^4.0.4" } }, "sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw=="],
@@ -4020,7 +4020,7 @@
"undici": ["undici@7.25.0", "", {}, "sha512-xXnp4kTyor2Zq+J1FfPI6Eq3ew5h6Vl0F/8d9XU5zZQf1tX9s2Su1/3PiMmUANFULpmksxkClamIZcaUqryHsQ=="],
- "undici-types": ["undici-types@7.19.2", "", {}, "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg=="],
+ "undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
"unicorn-magic": ["unicorn-magic@0.3.0", "", {}, "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA=="],
@@ -4272,11 +4272,7 @@
"@inkeep/cxkit-styled/tailwind-merge": ["tailwind-merge@2.6.0", "", {}, "sha512-P+Vu1qXfzediirmHOC3xKGAYeZtPcV9g76X+xg2FD4tYgR71ewMA35Y3sCz3zhiN/dwefRpJX0yBcgwi1fXNQA=="],
- "@inkeep/open-knowledge/@types/node": ["@types/node@24.12.2", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-A1sre26ke7HDIuY/M23nd9gfB+nrmhtYyMINbjI1zHJxYteKR6qSMX56FsmjMcDb3SMcjJg5BiRRgOCC/yBD0g=="],
-
- "@inkeep/open-knowledge-desktop/@types/node": ["@types/node@24.12.2", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-A1sre26ke7HDIuY/M23nd9gfB+nrmhtYyMINbjI1zHJxYteKR6qSMX56FsmjMcDb3SMcjJg5BiRRgOCC/yBD0g=="],
-
- "@inkeep/open-knowledge-docs/@types/node": ["@types/node@24.12.2", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-A1sre26ke7HDIuY/M23nd9gfB+nrmhtYyMINbjI1zHJxYteKR6qSMX56FsmjMcDb3SMcjJg5BiRRgOCC/yBD0g=="],
+ "@inkeep/open-knowledge-core/@types/node": ["@types/node@25.6.0", "", { "dependencies": { "undici-types": "~7.19.0" } }, "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ=="],
"@inkeep/open-knowledge-docs/lucide-react": ["lucide-react@0.503.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-HGGkdlPWQ0vTF8jJ5TdIqhQXZi6uh3LnNgfZ8MHiuxFfX3RZeA79r2MW2tHAZKlAVfoNE8esm3p+O6VkIvpj6w=="],
@@ -4302,6 +4298,8 @@
"@isaacs/cliui/wrap-ansi": ["wrap-ansi@8.1.0", "", { "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", "strip-ansi": "^7.0.1" } }, "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ=="],
+ "@jest/types/@types/node": ["@types/node@25.6.0", "", { "dependencies": { "undici-types": "~7.19.0" } }, "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ=="],
+
"@lingui/cli/jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="],
"@lingui/conf/jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="],
@@ -4414,23 +4412,13 @@
"@tiptap/starter-kit/@tiptap/pm": ["@tiptap/pm@3.22.3", "", { "dependencies": { "prosemirror-changeset": "^2.3.0", "prosemirror-collab": "^1.3.1", "prosemirror-commands": "^1.6.2", "prosemirror-dropcursor": "^1.8.1", "prosemirror-gapcursor": "^1.3.2", "prosemirror-history": "^1.4.1", "prosemirror-inputrules": "^1.4.0", "prosemirror-keymap": "^1.2.2", "prosemirror-markdown": "^1.13.1", "prosemirror-menu": "^1.2.4", "prosemirror-model": "^1.24.1", "prosemirror-schema-basic": "^1.2.3", "prosemirror-schema-list": "^1.5.0", "prosemirror-state": "^1.4.3", "prosemirror-tables": "^1.6.4", "prosemirror-trailing-node": "^3.0.0", "prosemirror-transform": "^1.10.2", "prosemirror-view": "^1.38.1" } }, "sha512-NjfWjZuvrqmpICT+GZWNIjtOdhPyqFKDMtQy7tsQ5rErM9L2ZQdy/+T/BKSO1JdTeBhdg9OP+0yfsqoYp2aT6A=="],
- "@types/busboy/@types/node": ["@types/node@24.12.2", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-A1sre26ke7HDIuY/M23nd9gfB+nrmhtYyMINbjI1zHJxYteKR6qSMX56FsmjMcDb3SMcjJg5BiRRgOCC/yBD0g=="],
-
- "@types/cacheable-request/@types/node": ["@types/node@24.12.2", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-A1sre26ke7HDIuY/M23nd9gfB+nrmhtYyMINbjI1zHJxYteKR6qSMX56FsmjMcDb3SMcjJg5BiRRgOCC/yBD0g=="],
-
- "@types/fs-extra/@types/node": ["@types/node@24.12.2", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-A1sre26ke7HDIuY/M23nd9gfB+nrmhtYyMINbjI1zHJxYteKR6qSMX56FsmjMcDb3SMcjJg5BiRRgOCC/yBD0g=="],
+ "@types/jsdom/@types/node": ["@types/node@25.6.0", "", { "dependencies": { "undici-types": "~7.19.0" } }, "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ=="],
"@types/jsdom/undici-types": ["undici-types@7.25.0", "", {}, "sha512-AXNgS1Byr27fTI+2bsPEkV9CxkT8H6xNyRI68b3TatlZo3RkzlqQBLL+w7SmGPVpokjHbcuNVQUWE7FRTg+LRA=="],
- "@types/keyv/@types/node": ["@types/node@24.12.2", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-A1sre26ke7HDIuY/M23nd9gfB+nrmhtYyMINbjI1zHJxYteKR6qSMX56FsmjMcDb3SMcjJg5BiRRgOCC/yBD0g=="],
-
- "@types/plist/@types/node": ["@types/node@24.12.2", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-A1sre26ke7HDIuY/M23nd9gfB+nrmhtYyMINbjI1zHJxYteKR6qSMX56FsmjMcDb3SMcjJg5BiRRgOCC/yBD0g=="],
-
- "@types/responselike/@types/node": ["@types/node@24.12.2", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-A1sre26ke7HDIuY/M23nd9gfB+nrmhtYyMINbjI1zHJxYteKR6qSMX56FsmjMcDb3SMcjJg5BiRRgOCC/yBD0g=="],
+ "@types/node-fetch/@types/node": ["@types/node@25.6.0", "", { "dependencies": { "undici-types": "~7.19.0" } }, "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ=="],
- "@types/ws/@types/node": ["@types/node@24.12.2", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-A1sre26ke7HDIuY/M23nd9gfB+nrmhtYyMINbjI1zHJxYteKR6qSMX56FsmjMcDb3SMcjJg5BiRRgOCC/yBD0g=="],
-
- "@types/yauzl/@types/node": ["@types/node@24.12.2", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-A1sre26ke7HDIuY/M23nd9gfB+nrmhtYyMINbjI1zHJxYteKR6qSMX56FsmjMcDb3SMcjJg5BiRRgOCC/yBD0g=="],
+ "@types/yazl/@types/node": ["@types/node@25.6.0", "", { "dependencies": { "undici-types": "~7.19.0" } }, "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ=="],
"ajv-keywords/ajv": ["ajv@6.14.0", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw=="],
@@ -4452,8 +4440,12 @@
"ast-kit/@babel/parser": ["@babel/parser@8.0.0-rc.3", "", { "dependencies": { "@babel/types": "^8.0.0-rc.3" }, "bin": "./bin/babel-parser.js" }, "sha512-B20dvP3MfNc/XS5KKCHy/oyWl5IA6Cn9YjXRdDlCjNmUFrjvLXMNUfQq/QUy9fnG2gYkKKcrto2YaF9B32ToOQ=="],
+ "buffer-image-size/@types/node": ["@types/node@25.6.0", "", { "dependencies": { "undici-types": "~7.19.0" } }, "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ=="],
+
"builder-util/fs-extra": ["fs-extra@10.1.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ=="],
+ "bun-types/@types/node": ["@types/node@25.6.0", "", { "dependencies": { "undici-types": "~7.19.0" } }, "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ=="],
+
"cacache/glob": ["glob@10.5.0", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg=="],
"cacache/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="],
@@ -4492,8 +4484,6 @@
"dotenv-expand/dotenv": ["dotenv@16.6.1", "", {}, "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow=="],
- "electron/@types/node": ["@types/node@24.12.2", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-A1sre26ke7HDIuY/M23nd9gfB+nrmhtYyMINbjI1zHJxYteKR6qSMX56FsmjMcDb3SMcjJg5BiRRgOCC/yBD0g=="],
-
"electron-builder/fs-extra": ["fs-extra@10.1.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ=="],
"electron-publish/fs-extra": ["fs-extra@10.1.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ=="],
@@ -4536,6 +4526,8 @@
"glob/minimatch": ["minimatch@3.1.5", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w=="],
+ "happy-dom/@types/node": ["@types/node@25.6.0", "", { "dependencies": { "undici-types": "~7.19.0" } }, "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ=="],
+
"happy-dom/whatwg-mimetype": ["whatwg-mimetype@3.0.0", "", {}, "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q=="],
"hast-util-from-html/parse5": ["parse5@7.3.0", "", { "dependencies": { "entities": "^6.0.0" } }, "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw=="],
@@ -4626,6 +4618,8 @@
"prosemirror-trailing-node/escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="],
+ "protobufjs/@types/node": ["@types/node@25.6.0", "", { "dependencies": { "undici-types": "~7.19.0" } }, "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ=="],
+
"proxy-addr/ipaddr.js": ["ipaddr.js@1.9.1", "", {}, "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="],
"proxy-agent/lru-cache": ["lru-cache@7.18.3", "", {}, "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA=="],
@@ -4844,11 +4838,9 @@
"@inkeep/cxkit-primitives/@radix-ui/react-tooltip/@radix-ui/react-visually-hidden": ["@radix-ui/react-visually-hidden@1.1.1", "", { "dependencies": { "@radix-ui/react-primitive": "2.0.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-vVfA2IZ9q/J+gEamvj761Oq1FpWgCDaNOOIfbPVp2MVPLEomUr5+Vf7kJGwQ24YxZSlQVar7Bes8kyTo5Dshpg=="],
- "@inkeep/open-knowledge-desktop/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
+ "@inkeep/open-knowledge-core/@types/node/undici-types": ["undici-types@7.19.2", "", {}, "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg=="],
- "@inkeep/open-knowledge-docs/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
-
- "@inkeep/open-knowledge/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
+ "@inkeep/open-knowledge-server/@types/yazl/@types/node": ["@types/node@25.6.0", "", { "dependencies": { "undici-types": "~7.19.0" } }, "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ=="],
"@inquirer/confirm/@inquirer/core/@inquirer/ansi": ["@inquirer/ansi@1.0.2", "", {}, "sha512-S8qNSZiYzFd0wAcyG5AXCvUHC5Sr7xpZ9wZ2py9XR88jUz8wooStVx5M6dRzczbBWjic9NP7+rY0Xi7qqK/aMQ=="],
@@ -4866,6 +4858,8 @@
"@isaacs/cliui/wrap-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="],
+ "@jest/types/@types/node/undici-types": ["undici-types@7.19.2", "", {}, "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg=="],
+
"@malept/flatpak-bundler/fs-extra/jsonfile": ["jsonfile@6.2.0", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg=="],
"@malept/flatpak-bundler/fs-extra/universalify": ["universalify@2.0.1", "", {}, "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw=="],
@@ -4908,21 +4902,11 @@
"@radix-ui/react-popover/@radix-ui/react-use-controllable-state/@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-jrBWOxZITuGcnjRCM2t2U5ZPkCLxD+Ym6DjfssS5haTj2iiak/DOb64JeN6OdLfLgptb6/e2kKR+ZuTrGoZTPA=="],
- "@types/busboy/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
-
- "@types/cacheable-request/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
-
- "@types/fs-extra/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
-
- "@types/keyv/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
-
- "@types/plist/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
-
- "@types/responselike/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
+ "@types/jsdom/@types/node/undici-types": ["undici-types@7.19.2", "", {}, "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg=="],
- "@types/ws/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
+ "@types/node-fetch/@types/node/undici-types": ["undici-types@7.19.2", "", {}, "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg=="],
- "@types/yauzl/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
+ "@types/yazl/@types/node/undici-types": ["undici-types@7.19.2", "", {}, "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg=="],
"ajv-keywords/ajv/json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="],
@@ -4942,10 +4926,14 @@
"ast-kit/@babel/parser/@babel/types": ["@babel/types@8.0.0-rc.3", "", { "dependencies": { "@babel/helper-string-parser": "^8.0.0-rc.3", "@babel/helper-validator-identifier": "^8.0.0-rc.3" } }, "sha512-mOm5ZrYmphGfqVWoH5YYMTITb3cDXsFgmvFlvkvWDMsR9X8RFnt7a0Wb6yNIdoFsiMO9WjYLq+U/FMtqIYAF8Q=="],
+ "buffer-image-size/@types/node/undici-types": ["undici-types@7.19.2", "", {}, "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg=="],
+
"builder-util/fs-extra/jsonfile": ["jsonfile@6.2.0", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg=="],
"builder-util/fs-extra/universalify": ["universalify@2.0.1", "", {}, "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw=="],
+ "bun-types/@types/node/undici-types": ["undici-types@7.19.2", "", {}, "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg=="],
+
"cacache/glob/minimatch": ["minimatch@9.0.9", "", { "dependencies": { "brace-expansion": "^2.0.2" } }, "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg=="],
"cli-truncate/string-width/strip-ansi": ["strip-ansi@7.2.0", "", { "dependencies": { "ansi-regex": "^6.2.2" } }, "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w=="],
@@ -4974,8 +4962,6 @@
"electron-updater/fs-extra/universalify": ["universalify@2.0.1", "", {}, "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw=="],
- "electron/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
-
"filelist/minimatch/brace-expansion": ["brace-expansion@2.1.0", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w=="],
"form-data/mime-types/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="],
@@ -5038,6 +5024,8 @@
"glob/minimatch/brace-expansion": ["brace-expansion@1.1.14", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g=="],
+ "happy-dom/@types/node/undici-types": ["undici-types@7.19.2", "", {}, "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg=="],
+
"hast-util-from-html/parse5/entities": ["entities@6.0.1", "", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="],
"hast-util-raw/parse5/entities": ["entities@6.0.1", "", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="],
@@ -5074,6 +5062,8 @@
"prebuild-install/tar-fs/tar-stream": ["tar-stream@2.2.0", "", { "dependencies": { "bl": "^4.0.3", "end-of-stream": "^1.4.1", "fs-constants": "^1.0.0", "inherits": "^2.0.3", "readable-stream": "^3.1.1" } }, "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ=="],
+ "protobufjs/@types/node/undici-types": ["undici-types@7.19.2", "", {}, "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg=="],
+
"puppeteer-core/chromium-bidi/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="],
"puppeteer/puppeteer-core/webdriver-bidi-protocol": ["webdriver-bidi-protocol@0.4.1", "", {}, "sha512-ARrjNjtWRRs2w4Tk7nqrf2gBI0QXWuOmMCx2hU+1jUt6d00MjMxURrhxhGbrsoiZKJrhTSTzbIrc554iKI10qw=="],
@@ -5264,6 +5254,8 @@
"@inkeep/cxkit-primitives/@radix-ui/react-tooltip/@radix-ui/react-use-controllable-state/@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.1.0", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw=="],
+ "@inkeep/open-knowledge-server/@types/yazl/@types/node/undici-types": ["undici-types@7.19.2", "", {}, "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg=="],
+
"@opentelemetry/instrumentation-fetch/@opentelemetry/sdk-trace-web/@opentelemetry/sdk-trace-base/@opentelemetry/resources": ["@opentelemetry/resources@2.1.0", "", { "dependencies": { "@opentelemetry/core": "2.1.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-1CJjf3LCvoefUOgegxi8h6r4B/wLSzInyhGP2UmIBYNlo4Qk5CZ73e1eEyWmfXvFtm1ybkmfb2DqWvspsYLrWw=="],
"app-builder-lib/@electron/fuses/fs-extra/jsonfile": ["jsonfile@6.2.0", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg=="],
diff --git a/packages/app/src/components/settings/EmbeddingsKeySection.tsx b/packages/app/src/components/settings/EmbeddingsKeySection.tsx
index 3465833a..613c6710 100644
--- a/packages/app/src/components/settings/EmbeddingsKeySection.tsx
+++ b/packages/app/src/components/settings/EmbeddingsKeySection.tsx
@@ -57,13 +57,13 @@ export function EmbeddingsKeySection({ transport }: { transport?: EmbeddingsKeyT
- Your OpenAI API key, used only to create embeddings of your content for semantic search.
- Stored once for this machine in{' '}
+ Your embeddings provider API key, used only to create embeddings of your content for
+ semantic search. Stored once for this machine in{' '}
~/.ok/secrets.yml
{' '}
(readable only by your user account) and shared across all projects. Turn the feature on
- per project in This project → Search.
+ per project in This project → Search, where you can also override the endpoint.
diff --git a/packages/app/src/components/settings/SearchSection.dom.test.tsx b/packages/app/src/components/settings/SearchSection.dom.test.tsx
index 29c7385c..11a8a56e 100644
--- a/packages/app/src/components/settings/SearchSection.dom.test.tsx
+++ b/packages/app/src/components/settings/SearchSection.dom.test.tsx
@@ -1,5 +1,10 @@
import { afterEach, beforeEach, describe, expect, mock, test } from 'bun:test';
-import type { Config, ConfigBinding, SemanticIndexStatus } from '@inkeep/open-knowledge-core';
+import {
+ DEFAULT_EMBEDDINGS_BASE_URL,
+ type Config,
+ type ConfigBinding,
+ type SemanticIndexStatus,
+} from '@inkeep/open-knowledge-core';
import { cleanup, render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
@@ -44,8 +49,14 @@ mock.module('@/lib/config-provider', () => ({
const { SearchSection } = await import('./SearchSection');
-function configWithSemanticEnabled(enabled: boolean): Config {
- return { search: { semantic: { enabled } } } as unknown as Config;
+function configWithSemantic({
+ enabled,
+ baseUrl,
+}: {
+ enabled: boolean;
+ baseUrl?: string;
+}): Config {
+ return { search: { semantic: { enabled, ...(baseUrl ? { baseUrl } : {}) } } } as unknown as Config;
}
function makeBinding(): { binding: ConfigBinding; calls: unknown[] } {
@@ -87,7 +98,7 @@ describe('SearchSection', () => {
test('off: switch is unchecked, body says no content leaves, no coverage panel', () => {
const { binding } = makeBinding();
mockProjectLocalBinding = binding;
- mockProjectLocalConfig = configWithSemanticEnabled(false);
+ mockProjectLocalConfig = configWithSemantic({ enabled: false });
render( );
@@ -115,7 +126,7 @@ describe('SearchSection', () => {
const user = userEvent.setup();
const { binding, calls } = makeBinding();
mockProjectLocalBinding = binding;
- mockProjectLocalConfig = configWithSemanticEnabled(false);
+ mockProjectLocalConfig = configWithSemantic({ enabled: false });
render( );
@@ -133,7 +144,7 @@ describe('SearchSection', () => {
const user = userEvent.setup();
const { binding, calls } = makeBinding();
mockProjectLocalBinding = binding;
- mockProjectLocalConfig = configWithSemanticEnabled(true);
+ mockProjectLocalConfig = configWithSemantic({ enabled: true });
mockStatus = {
enabled: true,
keyPresent: true,
@@ -155,7 +166,7 @@ describe('SearchSection', () => {
test('on + keyed + warmed + capable: shows read-only coverage', async () => {
const { binding } = makeBinding();
mockProjectLocalBinding = binding;
- mockProjectLocalConfig = configWithSemanticEnabled(true);
+ mockProjectLocalConfig = configWithSemantic({ enabled: true });
mockStatus = {
enabled: true,
keyPresent: true,
@@ -175,7 +186,7 @@ describe('SearchSection', () => {
test('on + capable but nothing embedded yet: shows the lazy-warm hint', async () => {
const { binding } = makeBinding();
mockProjectLocalBinding = binding;
- mockProjectLocalConfig = configWithSemanticEnabled(true);
+ mockProjectLocalConfig = configWithSemantic({ enabled: true });
mockStatus = {
enabled: true,
keyPresent: true,
@@ -195,7 +206,7 @@ describe('SearchSection', () => {
test('on + NO key: shows the needs-a-key hint pointing at Account (instant, no warm)', async () => {
const { binding } = makeBinding();
mockProjectLocalBinding = binding;
- mockProjectLocalConfig = configWithSemanticEnabled(true);
+ mockProjectLocalConfig = configWithSemantic({ enabled: true });
mockStatus = {
enabled: true,
keyPresent: false,
@@ -218,7 +229,7 @@ describe('SearchSection', () => {
test('on + key present but provider rejected it: shows the provider-error hint', async () => {
const { binding } = makeBinding();
mockProjectLocalBinding = binding;
- mockProjectLocalConfig = configWithSemanticEnabled(true);
+ mockProjectLocalConfig = configWithSemantic({ enabled: true });
mockStatus = {
enabled: true,
keyPresent: true,
@@ -239,7 +250,7 @@ describe('SearchSection', () => {
test('on + keyed but not warmed: shows the pending state', async () => {
const { binding } = makeBinding();
mockProjectLocalBinding = binding;
- mockProjectLocalConfig = configWithSemanticEnabled(true);
+ mockProjectLocalConfig = configWithSemantic({ enabled: true });
mockStatus = {
enabled: true,
keyPresent: true,
@@ -285,7 +296,7 @@ describe('SearchSection', () => {
const user = userEvent.setup();
const { binding, calls } = makeBinding();
mockProjectLocalBinding = binding;
- mockProjectLocalConfig = configWithSemanticEnabled(false);
+ mockProjectLocalConfig = configWithSemantic({ enabled: false });
render( );
@@ -305,7 +316,7 @@ describe('SearchSection', () => {
patch: () => ({ ok: false, error: { code: 'noop', message: 'fail' } }),
} as unknown as ConfigBinding;
mockProjectLocalBinding = failBinding;
- mockProjectLocalConfig = configWithSemanticEnabled(false);
+ mockProjectLocalConfig = configWithSemantic({ enabled: false });
render( );
@@ -314,4 +325,54 @@ describe('SearchSection', () => {
expect(await screen.findByTestId('settings-search-confirm')).toBeDefined();
});
+
+ test('shows the default endpoint when no custom provider is configured', () => {
+ const { binding } = makeBinding();
+ mockProjectLocalBinding = binding;
+ mockProjectLocalConfig = configWithSemantic({ enabled: false });
+
+ render( );
+
+ expect((screen.getByTestId('settings-search-base-url') as HTMLInputElement).value).toBe(
+ DEFAULT_EMBEDDINGS_BASE_URL,
+ );
+ });
+
+ test('blurring the endpoint field writes the trimmed custom base URL', async () => {
+ const user = userEvent.setup();
+ const { binding, calls } = makeBinding();
+ mockProjectLocalBinding = binding;
+ mockProjectLocalConfig = configWithSemantic({ enabled: false });
+
+ render( );
+
+ const input = screen.getByTestId('settings-search-base-url');
+ await user.clear(input);
+ await user.type(input, ' https://azure.example.com/openai/v1/ ');
+ await user.tab();
+
+ expect(calls).toContainEqual({
+ search: { semantic: { baseUrl: 'https://azure.example.com/openai/v1/' } },
+ });
+ });
+
+ test('clearing the endpoint field resets it to the default OpenAI endpoint', async () => {
+ const user = userEvent.setup();
+ const { binding, calls } = makeBinding();
+ mockProjectLocalBinding = binding;
+ mockProjectLocalConfig = configWithSemantic({
+ enabled: false,
+ baseUrl: 'https://azure.example.com/openai/v1',
+ });
+
+ render( );
+
+ const input = screen.getByTestId('settings-search-base-url');
+ await user.clear(input);
+ await user.tab();
+
+ expect(calls).toContainEqual({
+ search: { semantic: { baseUrl: DEFAULT_EMBEDDINGS_BASE_URL } },
+ });
+ });
});
diff --git a/packages/app/src/components/settings/SearchSection.tsx b/packages/app/src/components/settings/SearchSection.tsx
index 99ef2fe0..217fc14c 100644
--- a/packages/app/src/components/settings/SearchSection.tsx
+++ b/packages/app/src/components/settings/SearchSection.tsx
@@ -1,4 +1,4 @@
-import { humanFormat } from '@inkeep/open-knowledge-core';
+import { DEFAULT_EMBEDDINGS_BASE_URL, humanFormat } from '@inkeep/open-knowledge-core';
import { Trans, useLingui } from '@lingui/react/macro';
import { useEffect, useRef, useState } from 'react';
import { toast } from 'sonner';
@@ -13,6 +13,7 @@ import {
Dialog as DialogRoot,
DialogTitle,
} from '@/components/ui/dialog';
+import { Input } from '@/components/ui/input';
import { Switch } from '@/components/ui/switch';
import { useSemanticSearchStatus } from '@/hooks/use-semantic-search-status';
import { useConfigContext } from '@/lib/config-provider';
@@ -24,6 +25,7 @@ export function SearchSection() {
const { projectLocalConfig, projectLocalSynced, projectLocalBinding } = useConfigContext();
const { status, refresh } = useSemanticSearchStatus();
const [confirmOpen, setConfirmOpen] = useState(false);
+ const [baseUrlInput, setBaseUrlInput] = useState(DEFAULT_EMBEDDINGS_BASE_URL);
const settleTimersRef = useRef>>([]);
useEffect(
@@ -33,6 +35,13 @@ export function SearchSection() {
[],
);
+ const configuredBaseUrl =
+ projectLocalConfig?.search?.semantic?.baseUrl ?? DEFAULT_EMBEDDINGS_BASE_URL;
+
+ useEffect(() => {
+ setBaseUrlInput(configuredBaseUrl);
+ }, [configuredBaseUrl]);
+
const enabled = projectLocalConfig?.search?.semantic?.enabled ?? false;
const bindingReady = projectLocalSynced && projectLocalBinding !== null;
@@ -61,6 +70,28 @@ export function SearchSection() {
return true;
}
+ function writeBaseUrl(next: string): boolean {
+ if (projectLocalBinding === null) {
+ toast.error(t`Search settings not yet loaded — try again in a moment`);
+ return false;
+ }
+ const normalized = next.trim() || DEFAULT_EMBEDDINGS_BASE_URL;
+ if (normalized === configuredBaseUrl) {
+ setBaseUrlInput(normalized);
+ return true;
+ }
+ const result = projectLocalBinding.patch({ search: { semantic: { baseUrl: normalized } } });
+ if (!result.ok) {
+ const detail = humanFormat(result.error);
+ toast.error(t`Failed to update the embeddings endpoint — ${detail}`);
+ return false;
+ }
+ setBaseUrlInput(normalized);
+ refresh();
+ scheduleSettleRefresh();
+ return true;
+ }
+
function onToggleRequest(next: boolean) {
if (next) {
setConfirmOpen(true);
@@ -73,6 +104,10 @@ export function SearchSection() {
if (write(true)) setConfirmOpen(false);
}
+ function onBaseUrlBlur() {
+ writeBaseUrl(baseUrlInput);
+ }
+
const serverEnabled = status?.enabled ?? false;
const keyPresent = status?.keyPresent ?? false;
const ready = status?.ready ?? false;
@@ -138,6 +173,41 @@ export function SearchSection() {
) : null}
+
+
+
+ Embeddings API endpoint
+
+
+
+ Use the default OpenAI endpoint or override it with an OpenAI-compatible base URL for
+ Azure or a self-hosted provider.
+
+
+
+
setBaseUrlInput(e.target.value)}
+ onBlur={onBaseUrlBlur}
+ onKeyDown={(e) => {
+ if (e.key === 'Enter') {
+ e.preventDefault();
+ writeBaseUrl(baseUrlInput);
+ }
+ }}
+ placeholder={DEFAULT_EMBEDDINGS_BASE_URL}
+ disabled={!bindingReady}
+ spellCheck={false}
+ autoComplete="off"
+ data-testid="settings-search-base-url"
+ className="h-8 font-mono text-sm"
+ />
+
+ Clear the field to reset back to the default OpenAI endpoint.
+
+
+
{
for await (const chunk of process.stdin) chunks.push(chunk as Buffer);
return Buffer.concat(chunks).toString('utf-8').trim();
}
- return (await password({ message: 'Enter OpenAI embeddings API key:' })).trim();
+ return (await password({ message: 'Enter embeddings provider API key:' })).trim();
}
function readSemanticConfig(projectDir: string) {
@@ -57,7 +57,7 @@ async function fetchLiveCoverage(
function setKeyCommand(): Command {
return new Command('set-key')
- .description('Store your OpenAI embeddings API key in ~/.ok/secrets.yml')
+ .description('Store your embeddings provider API key in ~/.ok/secrets.yml')
.action(async () => {
const key = await readKey();
if (!key) {
@@ -67,9 +67,9 @@ function setKeyCommand(): Command {
}
await createEmbeddingsSecretStore().set(key);
process.stderr.write(
- '✓ OpenAI embeddings API key stored in ~/.ok/secrets.yml (0600, this machine only).\n' +
+ '✓ Embeddings provider API key stored in ~/.ok/secrets.yml (0600, this machine only).\n' +
'Now enable it per project — the easiest path is OK Desktop → Settings → This\n' +
- 'project → Search (a toggle with an egress-confirmation prompt), or run\n' +
+ 'project → Search (toggle + endpoint settings), or run\n' +
'`ok embeddings enable` in the project folder.\n',
);
});
@@ -77,14 +77,14 @@ function setKeyCommand(): Command {
function clearKeyCommand(): Command {
return new Command('clear-key')
- .description('Remove your stored OpenAI embeddings API key')
+ .description('Remove your stored embeddings provider API key')
.action(async () => {
const { touched } = await clearEmbeddingsKeyFromAllBackends();
if (touched.length === 0) {
- process.stderr.write('No stored OpenAI embeddings key found.\n');
+ process.stderr.write('No stored embeddings provider key found.\n');
return;
}
- process.stderr.write(`✓ OpenAI embeddings API key cleared (${touched.join(', ')}).\n`);
+ process.stderr.write(`✓ Embeddings provider API key cleared (${touched.join(', ')}).\n`);
});
}
From e9839e119382a515a284ffcd5e335e4778fa0611 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sat, 27 Jun 2026 08:43:00 +0000
Subject: [PATCH 2/5] test: cover embeddings endpoint settings
---
.changeset/custom-embeddings-endpoint.md | 5 +++++
.../app/src/components/settings/SearchSection.dom.test.tsx | 2 +-
2 files changed, 6 insertions(+), 1 deletion(-)
create mode 100644 .changeset/custom-embeddings-endpoint.md
diff --git a/.changeset/custom-embeddings-endpoint.md b/.changeset/custom-embeddings-endpoint.md
new file mode 100644
index 00000000..2ae779d7
--- /dev/null
+++ b/.changeset/custom-embeddings-endpoint.md
@@ -0,0 +1,5 @@
+---
+"@inkeep/open-knowledge": patch
+---
+
+Configure a custom OpenAI-compatible embeddings endpoint from Settings → This project → Search instead of editing config files by hand. The semantic-search settings now expose the embeddings base URL directly, and the account copy plus `ok embeddings set-key` messaging now describe the key as belonging to the configured embeddings provider rather than only to OpenAI.
diff --git a/packages/app/src/components/settings/SearchSection.dom.test.tsx b/packages/app/src/components/settings/SearchSection.dom.test.tsx
index 11a8a56e..71b9b1f0 100644
--- a/packages/app/src/components/settings/SearchSection.dom.test.tsx
+++ b/packages/app/src/components/settings/SearchSection.dom.test.tsx
@@ -272,7 +272,7 @@ describe('SearchSection', () => {
test('on but server not yet settled: shows the applying state', async () => {
const { binding } = makeBinding();
mockProjectLocalBinding = binding;
- mockProjectLocalConfig = configWithSemanticEnabled(true);
+ mockProjectLocalConfig = configWithSemantic({ enabled: true });
mockStatus = {
enabled: false,
keyPresent: false,
From d77b066d471f10769998c69afef914ea44efd25a Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sat, 27 Jun 2026 08:50:08 +0000
Subject: [PATCH 3/5] feat: expose embeddings endpoint in settings
---
.../settings/SearchSection.dom.test.tsx | 14 +++-----
.../src/components/settings/SearchSection.tsx | 33 ++++++++-----------
packages/app/src/locales/en/messages.json | 12 +++++--
packages/app/src/locales/en/messages.po | 24 +++++++++++---
packages/app/src/locales/pseudo/messages.json | 12 +++++--
packages/app/src/locales/pseudo/messages.po | 24 +++++++++++---
6 files changed, 77 insertions(+), 42 deletions(-)
diff --git a/packages/app/src/components/settings/SearchSection.dom.test.tsx b/packages/app/src/components/settings/SearchSection.dom.test.tsx
index 71b9b1f0..d2dc2103 100644
--- a/packages/app/src/components/settings/SearchSection.dom.test.tsx
+++ b/packages/app/src/components/settings/SearchSection.dom.test.tsx
@@ -1,8 +1,8 @@
import { afterEach, beforeEach, describe, expect, mock, test } from 'bun:test';
import {
- DEFAULT_EMBEDDINGS_BASE_URL,
type Config,
type ConfigBinding,
+ DEFAULT_EMBEDDINGS_BASE_URL,
type SemanticIndexStatus,
} from '@inkeep/open-knowledge-core';
import { cleanup, render, screen, waitFor } from '@testing-library/react';
@@ -49,14 +49,10 @@ mock.module('@/lib/config-provider', () => ({
const { SearchSection } = await import('./SearchSection');
-function configWithSemantic({
- enabled,
- baseUrl,
-}: {
- enabled: boolean;
- baseUrl?: string;
-}): Config {
- return { search: { semantic: { enabled, ...(baseUrl ? { baseUrl } : {}) } } } as unknown as Config;
+function configWithSemantic({ enabled, baseUrl }: { enabled: boolean; baseUrl?: string }): Config {
+ return {
+ search: { semantic: { enabled, ...(baseUrl ? { baseUrl } : {}) } },
+ } as unknown as Config;
}
function makeBinding(): { binding: ConfigBinding; calls: unknown[] } {
diff --git a/packages/app/src/components/settings/SearchSection.tsx b/packages/app/src/components/settings/SearchSection.tsx
index 217fc14c..013c9b71 100644
--- a/packages/app/src/components/settings/SearchSection.tsx
+++ b/packages/app/src/components/settings/SearchSection.tsx
@@ -25,7 +25,6 @@ export function SearchSection() {
const { projectLocalConfig, projectLocalSynced, projectLocalBinding } = useConfigContext();
const { status, refresh } = useSemanticSearchStatus();
const [confirmOpen, setConfirmOpen] = useState(false);
- const [baseUrlInput, setBaseUrlInput] = useState(DEFAULT_EMBEDDINGS_BASE_URL);
const settleTimersRef = useRef>>([]);
useEffect(
@@ -38,10 +37,6 @@ export function SearchSection() {
const configuredBaseUrl =
projectLocalConfig?.search?.semantic?.baseUrl ?? DEFAULT_EMBEDDINGS_BASE_URL;
- useEffect(() => {
- setBaseUrlInput(configuredBaseUrl);
- }, [configuredBaseUrl]);
-
const enabled = projectLocalConfig?.search?.semantic?.enabled ?? false;
const bindingReady = projectLocalSynced && projectLocalBinding !== null;
@@ -70,23 +65,23 @@ export function SearchSection() {
return true;
}
+ function normalizeBaseUrl(next: string): string {
+ return next.trim() || DEFAULT_EMBEDDINGS_BASE_URL;
+ }
+
function writeBaseUrl(next: string): boolean {
if (projectLocalBinding === null) {
toast.error(t`Search settings not yet loaded — try again in a moment`);
return false;
}
- const normalized = next.trim() || DEFAULT_EMBEDDINGS_BASE_URL;
- if (normalized === configuredBaseUrl) {
- setBaseUrlInput(normalized);
- return true;
- }
+ const normalized = normalizeBaseUrl(next);
+ if (normalized === configuredBaseUrl) return true;
const result = projectLocalBinding.patch({ search: { semantic: { baseUrl: normalized } } });
if (!result.ok) {
const detail = humanFormat(result.error);
toast.error(t`Failed to update the embeddings endpoint — ${detail}`);
return false;
}
- setBaseUrlInput(normalized);
refresh();
scheduleSettleRefresh();
return true;
@@ -104,10 +99,6 @@ export function SearchSection() {
if (write(true)) setConfirmOpen(false);
}
- function onBaseUrlBlur() {
- writeBaseUrl(baseUrlInput);
- }
-
const serverEnabled = status?.enabled ?? false;
const keyPresent = status?.keyPresent ?? false;
const ready = status?.ready ?? false;
@@ -186,14 +177,18 @@ export function SearchSection() {
setBaseUrlInput(e.target.value)}
- onBlur={onBaseUrlBlur}
+ defaultValue={configuredBaseUrl}
+ onBlur={(e) => {
+ const normalized = normalizeBaseUrl(e.currentTarget.value);
+ if (writeBaseUrl(e.currentTarget.value)) e.currentTarget.value = normalized;
+ }}
onKeyDown={(e) => {
if (e.key === 'Enter') {
e.preventDefault();
- writeBaseUrl(baseUrlInput);
+ const normalized = normalizeBaseUrl(e.currentTarget.value);
+ if (writeBaseUrl(e.currentTarget.value)) e.currentTarget.value = normalized;
}
}}
placeholder={DEFAULT_EMBEDDINGS_BASE_URL}
diff --git a/packages/app/src/locales/en/messages.json b/packages/app/src/locales/en/messages.json
index 07c7e58f..65c6a9ba 100644
--- a/packages/app/src/locales/en/messages.json
+++ b/packages/app/src/locales/en/messages.json
@@ -594,9 +594,6 @@
"FEr96N": ["Theme"],
"FNTx6u": ["Search \"", ["semanticSubmitQuery"], "\" by meaning"],
"FOGD7m": ["Create something great."],
- "FOyCTr": [
- "Your OpenAI API key, used only to create embeddings of your content for semantic search. Stored once for this machine in <0>~/.ok/secrets.yml0> (readable only by your user account) and shared across all projects. Turn the feature on per project in This project → Search."
- ],
"FRYB1Q": ["/api/config returned a malformed body"],
"FRqZ9v": ["Couldn't update skill: ", ["0"]],
"FTUGgh": ["Enter a repository URL or owner/repo"],
@@ -770,6 +767,7 @@
"KujtjC": ["Find"],
"L-rMC9": ["Reset to default"],
"L1ZE3M": ["Document statistics"],
+ "L1rRuU": ["Embeddings API endpoint"],
"L3CEC1": ["this item"],
"L4Cdd9": ["or create a new file <0/>"],
"L6Hhh6": ["(root)"],
@@ -1403,6 +1401,7 @@
"eG8Jsg": ["Toggle source tab focus mode"],
"eJitUk": ["Upload from computer"],
"eKThTQ": ["Failed to reorder"],
+ "eLl1VX": ["Failed to update the embeddings endpoint — ", ["detail"]],
"eNQGRb": ["Inline LaTeX math rendered with KaTeX."],
"ePK91l": ["Edit"],
"eQkgKV": ["Installed"],
@@ -1618,6 +1617,7 @@
"l8G3S9": ["Auto-sync is off — you don't have permission to push to this repo"],
"lAiyU_": ["Only the current document uses <0>#", ["tag"], "0>."],
"lGs_bQ": ["Page <0>*0>"],
+ "lHCR4I": ["Clear the field to reset back to the default OpenAI endpoint."],
"lHwYMr": ["Server error: ", ["status"], " ", ["statusText"]],
"lI0Td2": ["Use letters, digits, <0>_0> and <1>-1> only."],
"lIn9L9": ["Disable sync"],
@@ -1785,6 +1785,9 @@
"pha01Y": ["Project-level pages with no incoming graph edges."],
"pkAft1": ["Search failed."],
"pmKdif": ["Failed: ", ["loadError"]],
+ "pmOGtg": [
+ "Use the default OpenAI endpoint or override it with an OpenAI-compatible base URL for Azure or a self-hosted provider."
+ ],
"pmUArF": ["Workspace"],
"ppDgFi": ["Restart with this app's version"],
"pzutoc": ["Italic"],
@@ -2002,6 +2005,9 @@
"wXO4Tg": [["hrs"], "h ago"],
"wbv9xO": ["Create new project"],
"wbwHYD": ["Enable sync"],
+ "wccmX0": [
+ "Your embeddings provider API key, used only to create embeddings of your content for semantic search. Stored once for this machine in <0>~/.ok/secrets.yml0> (readable only by your user account) and shared across all projects. Turn the feature on per project in This project → Search, where you can also override the endpoint."
+ ],
"weP6me": ["Couldn't load docs — type @ again to retry"],
"wlwXUk": [
"You picked ~/Downloads. Files there are usually transient — consider a stable folder instead."
diff --git a/packages/app/src/locales/en/messages.po b/packages/app/src/locales/en/messages.po
index f0a213a0..9025b572 100644
--- a/packages/app/src/locales/en/messages.po
+++ b/packages/app/src/locales/en/messages.po
@@ -1067,6 +1067,10 @@ msgstr "Clear"
msgid "Clear {keyName}"
msgstr "Clear {keyName}"
+#: src/components/settings/SearchSection.tsx
+msgid "Clear the field to reset back to the default OpenAI endpoint."
+msgstr "Clear the field to reset back to the default OpenAI endpoint."
+
#: src/components/FolderTimelineCard.tsx
msgid "cleared folder properties"
msgstr "cleared folder properties"
@@ -2325,6 +2329,10 @@ msgstr "Embed an external page in an inline iframe (docs, demos, Figma, CodeSand
msgid "Embed an image with optional alt text."
msgstr "Embed an image with optional alt text."
+#: src/components/settings/SearchSection.tsx
+msgid "Embeddings API endpoint"
+msgstr "Embeddings API endpoint"
+
#: src/components/settings/SearchSection.tsx
msgid "Embeddings are computed only when a search runs and are cached locally under <0>.ok/local0>."
msgstr "Embeddings are computed only when a search runs and are cached locally under <0>.ok/local0>."
@@ -2657,6 +2665,10 @@ msgstr "Failed to reorder"
msgid "Failed to update property"
msgstr "Failed to update property"
+#: src/components/settings/SearchSection.tsx
+msgid "Failed to update the embeddings endpoint — {detail}"
+msgstr "Failed to update the embeddings endpoint — {detail}"
+
#: src/components/settings/SettingsDialogBody.tsx
msgid "Failed to update the project sync default — {detail}"
msgstr "Failed to update the project sync default — {detail}"
@@ -6686,6 +6698,10 @@ msgstr "Use lowercase letters, digits, and <0>-0> only."
msgid "Use lowercase letters, digits, and hyphens only."
msgstr "Use lowercase letters, digits, and hyphens only."
+#: src/components/settings/SearchSection.tsx
+msgid "Use the default OpenAI endpoint or override it with an OpenAI-compatible base URL for Azure or a self-hosted provider."
+msgstr "Use the default OpenAI endpoint or override it with an OpenAI-compatible base URL for Azure or a self-hosted provider."
+
#: src/components/settings/SettingsDialogShell.tsx
msgid "User"
msgstr "User"
@@ -6914,6 +6930,10 @@ msgstr "You picked the filesystem root (/). Scaffolding here will scan every fil
msgid "You picked your home directory. OpenKnowledge will index everything in your home tree — large and may surface personal files."
msgstr "You picked your home directory. OpenKnowledge will index everything in your home tree — large and may surface personal files."
+#: src/components/settings/EmbeddingsKeySection.tsx
+msgid "Your embeddings provider API key, used only to create embeddings of your content for semantic search. Stored once for this machine in <0>~/.ok/secrets.yml0> (readable only by your user account) and shared across all projects. Turn the feature on per project in This project → Search, where you can also override the endpoint."
+msgstr "Your embeddings provider API key, used only to create embeddings of your content for semantic search. Stored once for this machine in <0>~/.ok/secrets.yml0> (readable only by your user account) and shared across all projects. Turn the feature on per project in This project → Search, where you can also override the endpoint."
+
#: src/components/settings/SettingsDialogBody.tsx
#: src/components/SyncStatusBadge.tsx
msgid "Your GitHub session expired — sign in again to verify push access."
@@ -6927,10 +6947,6 @@ msgstr "Your GitHub token is missing required scopes. Try signing in again."
msgid "Your knowledge base is now on GitHub at <0>{ownerLogin}/{repoName}0>."
msgstr "Your knowledge base is now on GitHub at <0>{ownerLogin}/{repoName}0>."
-#: src/components/settings/EmbeddingsKeySection.tsx
-msgid "Your OpenAI API key, used only to create embeddings of your content for semantic search. Stored once for this machine in <0>~/.ok/secrets.yml0> (readable only by your user account) and shared across all projects. Turn the feature on per project in This project → Search."
-msgstr "Your OpenAI API key, used only to create embeddings of your content for semantic search. Stored once for this machine in <0>~/.ok/secrets.yml0> (readable only by your user account) and shared across all projects. Turn the feature on per project in This project → Search."
-
#: src/components/CloneDialog.tsx
msgid "Your repositories"
msgstr "Your repositories"
diff --git a/packages/app/src/locales/pseudo/messages.json b/packages/app/src/locales/pseudo/messages.json
index f3e59392..717e55fc 100644
--- a/packages/app/src/locales/pseudo/messages.json
+++ b/packages/app/src/locales/pseudo/messages.json
@@ -594,9 +594,6 @@
"FEr96N": ["Ţĥēḿē"],
"FNTx6u": ["Śēàŕćĥ \"", ["semanticSubmitQuery"], "\" ƀŷ ḿēàńĩńĝ"],
"FOGD7m": ["Ćŕēàţē śōḿēţĥĩńĝ ĝŕēàţ."],
- "FOyCTr": [
- "Ŷōũŕ ŌƥēńÀĨ ÀƤĨ ķēŷ, ũśēď ōńĺŷ ţō ćŕēàţē ēḿƀēďďĩńĝś ōƒ ŷōũŕ ćōńţēńţ ƒōŕ śēḿàńţĩć śēàŕćĥ. Śţōŕēď ōńćē ƒōŕ ţĥĩś ḿàćĥĩńē ĩń <0>~/.ōķ/śēćŕēţś.ŷḿĺ0> (ŕēàďàƀĺē ōńĺŷ ƀŷ ŷōũŕ ũśēŕ àććōũńţ) àńď śĥàŕēď àćŕōśś àĺĺ ƥŕōĴēćţś. Ţũŕń ţĥē ƒēàţũŕē ōń ƥēŕ ƥŕōĴēćţ ĩń Ţĥĩś ƥŕōĴēćţ → Śēàŕćĥ."
- ],
"FRYB1Q": ["/àƥĩ/ćōńƒĩĝ ŕēţũŕńēď à ḿàĺƒōŕḿēď ƀōďŷ"],
"FRqZ9v": ["Ćōũĺďń'ţ ũƥďàţē śķĩĺĺ: ", ["0"]],
"FTUGgh": ["Ēńţēŕ à ŕēƥōśĩţōŕŷ ŨŔĹ ōŕ ōŵńēŕ/ŕēƥō"],
@@ -770,6 +767,7 @@
"KujtjC": ["Ƒĩńď"],
"L-rMC9": ["Ŕēśēţ ţō ďēƒàũĺţ"],
"L1ZE3M": ["Ďōćũḿēńţ śţàţĩśţĩćś"],
+ "L1rRuU": ["Ēḿƀēďďĩńĝś ÀƤĨ ēńďƥōĩńţ"],
"L3CEC1": ["ţĥĩś ĩţēḿ"],
"L4Cdd9": ["ōŕ ćŕēàţē à ńēŵ ƒĩĺē <0/>"],
"L6Hhh6": ["(ŕōōţ)"],
@@ -1403,6 +1401,7 @@
"eG8Jsg": ["Ţōĝĝĺē śōũŕćē ţàƀ ƒōćũś ḿōďē"],
"eJitUk": ["Ũƥĺōàď ƒŕōḿ ćōḿƥũţēŕ"],
"eKThTQ": ["Ƒàĩĺēď ţō ŕēōŕďēŕ"],
+ "eLl1VX": ["Ƒàĩĺēď ţō ũƥďàţē ţĥē ēḿƀēďďĩńĝś ēńďƥōĩńţ — ", ["detail"]],
"eNQGRb": ["Ĩńĺĩńē ĹàŢēX ḿàţĥ ŕēńďēŕēď ŵĩţĥ ĶàŢēX."],
"ePK91l": ["Ēďĩţ"],
"eQkgKV": ["Ĩńśţàĺĺēď"],
@@ -1618,6 +1617,7 @@
"l8G3S9": ["Àũţō-śŷńć ĩś ōƒƒ — ŷōũ ďōń'ţ ĥàvē ƥēŕḿĩśśĩōń ţō ƥũśĥ ţō ţĥĩś ŕēƥō"],
"lAiyU_": ["Ōńĺŷ ţĥē ćũŕŕēńţ ďōćũḿēńţ ũśēś <0>#", ["tag"], "0>."],
"lGs_bQ": ["Ƥàĝē <0>*0>"],
+ "lHCR4I": ["Ćĺēàŕ ţĥē ƒĩēĺď ţō ŕēśēţ ƀàćķ ţō ţĥē ďēƒàũĺţ ŌƥēńÀĨ ēńďƥōĩńţ."],
"lHwYMr": ["Śēŕvēŕ ēŕŕōŕ: ", ["status"], " ", ["statusText"]],
"lI0Td2": ["Ũśē ĺēţţēŕś, ďĩĝĩţś, <0>_0> àńď <1>-1> ōńĺŷ."],
"lIn9L9": ["Ďĩśàƀĺē śŷńć"],
@@ -1785,6 +1785,9 @@
"pha01Y": ["ƤŕōĴēćţ-ĺēvēĺ ƥàĝēś ŵĩţĥ ńō ĩńćōḿĩńĝ ĝŕàƥĥ ēďĝēś."],
"pkAft1": ["Śēàŕćĥ ƒàĩĺēď."],
"pmKdif": ["Ƒàĩĺēď: ", ["loadError"]],
+ "pmOGtg": [
+ "Ũśē ţĥē ďēƒàũĺţ ŌƥēńÀĨ ēńďƥōĩńţ ōŕ ōvēŕŕĩďē ĩţ ŵĩţĥ àń ŌƥēńÀĨ-ćōḿƥàţĩƀĺē ƀàśē ŨŔĹ ƒōŕ Àźũŕē ōŕ à śēĺƒ-ĥōśţēď ƥŕōvĩďēŕ."
+ ],
"pmUArF": ["Ŵōŕķśƥàćē"],
"ppDgFi": ["Ŕēśţàŕţ ŵĩţĥ ţĥĩś àƥƥ'ś vēŕśĩōń"],
"pzutoc": ["Ĩţàĺĩć"],
@@ -2002,6 +2005,9 @@
"wXO4Tg": [["hrs"], "ĥ àĝō"],
"wbv9xO": ["Ćŕēàţē ńēŵ ƥŕōĴēćţ"],
"wbwHYD": ["Ēńàƀĺē śŷńć"],
+ "wccmX0": [
+ "Ŷōũŕ ēḿƀēďďĩńĝś ƥŕōvĩďēŕ ÀƤĨ ķēŷ, ũśēď ōńĺŷ ţō ćŕēàţē ēḿƀēďďĩńĝś ōƒ ŷōũŕ ćōńţēńţ ƒōŕ śēḿàńţĩć śēàŕćĥ. Śţōŕēď ōńćē ƒōŕ ţĥĩś ḿàćĥĩńē ĩń <0>~/.ōķ/śēćŕēţś.ŷḿĺ0> (ŕēàďàƀĺē ōńĺŷ ƀŷ ŷōũŕ ũśēŕ àććōũńţ) àńď śĥàŕēď àćŕōśś àĺĺ ƥŕōĴēćţś. Ţũŕń ţĥē ƒēàţũŕē ōń ƥēŕ ƥŕōĴēćţ ĩń Ţĥĩś ƥŕōĴēćţ → Śēàŕćĥ, ŵĥēŕē ŷōũ ćàń àĺśō ōvēŕŕĩďē ţĥē ēńďƥōĩńţ."
+ ],
"weP6me": ["Ćōũĺďń'ţ ĺōàď ďōćś — ţŷƥē @ àĝàĩń ţō ŕēţŕŷ"],
"wlwXUk": [
"Ŷōũ ƥĩćķēď ~/Ďōŵńĺōàďś. Ƒĩĺēś ţĥēŕē àŕē ũśũàĺĺŷ ţŕàńśĩēńţ — ćōńśĩďēŕ à śţàƀĺē ƒōĺďēŕ ĩńśţēàď."
diff --git a/packages/app/src/locales/pseudo/messages.po b/packages/app/src/locales/pseudo/messages.po
index 2a401405..84d83e31 100644
--- a/packages/app/src/locales/pseudo/messages.po
+++ b/packages/app/src/locales/pseudo/messages.po
@@ -1062,6 +1062,10 @@ msgstr ""
msgid "Clear {keyName}"
msgstr ""
+#: src/components/settings/SearchSection.tsx
+msgid "Clear the field to reset back to the default OpenAI endpoint."
+msgstr ""
+
#: src/components/FolderTimelineCard.tsx
msgid "cleared folder properties"
msgstr ""
@@ -2320,6 +2324,10 @@ msgstr ""
msgid "Embed an image with optional alt text."
msgstr ""
+#: src/components/settings/SearchSection.tsx
+msgid "Embeddings API endpoint"
+msgstr ""
+
#: src/components/settings/SearchSection.tsx
msgid "Embeddings are computed only when a search runs and are cached locally under <0>.ok/local0>."
msgstr ""
@@ -2652,6 +2660,10 @@ msgstr ""
msgid "Failed to update property"
msgstr ""
+#: src/components/settings/SearchSection.tsx
+msgid "Failed to update the embeddings endpoint — {detail}"
+msgstr ""
+
#: src/components/settings/SettingsDialogBody.tsx
msgid "Failed to update the project sync default — {detail}"
msgstr ""
@@ -6681,6 +6693,10 @@ msgstr ""
msgid "Use lowercase letters, digits, and hyphens only."
msgstr ""
+#: src/components/settings/SearchSection.tsx
+msgid "Use the default OpenAI endpoint or override it with an OpenAI-compatible base URL for Azure or a self-hosted provider."
+msgstr ""
+
#: src/components/settings/SettingsDialogShell.tsx
msgid "User"
msgstr ""
@@ -6909,6 +6925,10 @@ msgstr ""
msgid "You picked your home directory. OpenKnowledge will index everything in your home tree — large and may surface personal files."
msgstr ""
+#: src/components/settings/EmbeddingsKeySection.tsx
+msgid "Your embeddings provider API key, used only to create embeddings of your content for semantic search. Stored once for this machine in <0>~/.ok/secrets.yml0> (readable only by your user account) and shared across all projects. Turn the feature on per project in This project → Search, where you can also override the endpoint."
+msgstr ""
+
#: src/components/settings/SettingsDialogBody.tsx
#: src/components/SyncStatusBadge.tsx
msgid "Your GitHub session expired — sign in again to verify push access."
@@ -6922,10 +6942,6 @@ msgstr ""
msgid "Your knowledge base is now on GitHub at <0>{ownerLogin}/{repoName}0>."
msgstr ""
-#: src/components/settings/EmbeddingsKeySection.tsx
-msgid "Your OpenAI API key, used only to create embeddings of your content for semantic search. Stored once for this machine in <0>~/.ok/secrets.yml0> (readable only by your user account) and shared across all projects. Turn the feature on per project in This project → Search."
-msgstr ""
-
#: src/components/CloneDialog.tsx
msgid "Your repositories"
msgstr ""
From dddefeaab700bf8e5fc4b930cc3a8b9fee9d29f2 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sat, 27 Jun 2026 08:50:58 +0000
Subject: [PATCH 4/5] chore: restore bun lockfile
---
bun.lock | 74 +++++++++++++++++++++++++++++++-------------------------
1 file changed, 41 insertions(+), 33 deletions(-)
diff --git a/bun.lock b/bun.lock
index 46e5b191..64012d74 100644
--- a/bun.lock
+++ b/bun.lock
@@ -1774,7 +1774,7 @@
"@types/ms": ["@types/ms@2.1.0", "", {}, "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA=="],
- "@types/node": ["@types/node@24.12.2", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-A1sre26ke7HDIuY/M23nd9gfB+nrmhtYyMINbjI1zHJxYteKR6qSMX56FsmjMcDb3SMcjJg5BiRRgOCC/yBD0g=="],
+ "@types/node": ["@types/node@25.6.0", "", { "dependencies": { "undici-types": "~7.19.0" } }, "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ=="],
"@types/node-fetch": ["@types/node-fetch@2.6.13", "", { "dependencies": { "@types/node": "*", "form-data": "^4.0.4" } }, "sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw=="],
@@ -4020,7 +4020,7 @@
"undici": ["undici@7.25.0", "", {}, "sha512-xXnp4kTyor2Zq+J1FfPI6Eq3ew5h6Vl0F/8d9XU5zZQf1tX9s2Su1/3PiMmUANFULpmksxkClamIZcaUqryHsQ=="],
- "undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
+ "undici-types": ["undici-types@7.19.2", "", {}, "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg=="],
"unicorn-magic": ["unicorn-magic@0.3.0", "", {}, "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA=="],
@@ -4272,7 +4272,11 @@
"@inkeep/cxkit-styled/tailwind-merge": ["tailwind-merge@2.6.0", "", {}, "sha512-P+Vu1qXfzediirmHOC3xKGAYeZtPcV9g76X+xg2FD4tYgR71ewMA35Y3sCz3zhiN/dwefRpJX0yBcgwi1fXNQA=="],
- "@inkeep/open-knowledge-core/@types/node": ["@types/node@25.6.0", "", { "dependencies": { "undici-types": "~7.19.0" } }, "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ=="],
+ "@inkeep/open-knowledge/@types/node": ["@types/node@24.12.2", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-A1sre26ke7HDIuY/M23nd9gfB+nrmhtYyMINbjI1zHJxYteKR6qSMX56FsmjMcDb3SMcjJg5BiRRgOCC/yBD0g=="],
+
+ "@inkeep/open-knowledge-desktop/@types/node": ["@types/node@24.12.2", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-A1sre26ke7HDIuY/M23nd9gfB+nrmhtYyMINbjI1zHJxYteKR6qSMX56FsmjMcDb3SMcjJg5BiRRgOCC/yBD0g=="],
+
+ "@inkeep/open-knowledge-docs/@types/node": ["@types/node@24.12.2", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-A1sre26ke7HDIuY/M23nd9gfB+nrmhtYyMINbjI1zHJxYteKR6qSMX56FsmjMcDb3SMcjJg5BiRRgOCC/yBD0g=="],
"@inkeep/open-knowledge-docs/lucide-react": ["lucide-react@0.503.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-HGGkdlPWQ0vTF8jJ5TdIqhQXZi6uh3LnNgfZ8MHiuxFfX3RZeA79r2MW2tHAZKlAVfoNE8esm3p+O6VkIvpj6w=="],
@@ -4298,8 +4302,6 @@
"@isaacs/cliui/wrap-ansi": ["wrap-ansi@8.1.0", "", { "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", "strip-ansi": "^7.0.1" } }, "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ=="],
- "@jest/types/@types/node": ["@types/node@25.6.0", "", { "dependencies": { "undici-types": "~7.19.0" } }, "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ=="],
-
"@lingui/cli/jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="],
"@lingui/conf/jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="],
@@ -4412,13 +4414,23 @@
"@tiptap/starter-kit/@tiptap/pm": ["@tiptap/pm@3.22.3", "", { "dependencies": { "prosemirror-changeset": "^2.3.0", "prosemirror-collab": "^1.3.1", "prosemirror-commands": "^1.6.2", "prosemirror-dropcursor": "^1.8.1", "prosemirror-gapcursor": "^1.3.2", "prosemirror-history": "^1.4.1", "prosemirror-inputrules": "^1.4.0", "prosemirror-keymap": "^1.2.2", "prosemirror-markdown": "^1.13.1", "prosemirror-menu": "^1.2.4", "prosemirror-model": "^1.24.1", "prosemirror-schema-basic": "^1.2.3", "prosemirror-schema-list": "^1.5.0", "prosemirror-state": "^1.4.3", "prosemirror-tables": "^1.6.4", "prosemirror-trailing-node": "^3.0.0", "prosemirror-transform": "^1.10.2", "prosemirror-view": "^1.38.1" } }, "sha512-NjfWjZuvrqmpICT+GZWNIjtOdhPyqFKDMtQy7tsQ5rErM9L2ZQdy/+T/BKSO1JdTeBhdg9OP+0yfsqoYp2aT6A=="],
- "@types/jsdom/@types/node": ["@types/node@25.6.0", "", { "dependencies": { "undici-types": "~7.19.0" } }, "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ=="],
+ "@types/busboy/@types/node": ["@types/node@24.12.2", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-A1sre26ke7HDIuY/M23nd9gfB+nrmhtYyMINbjI1zHJxYteKR6qSMX56FsmjMcDb3SMcjJg5BiRRgOCC/yBD0g=="],
+
+ "@types/cacheable-request/@types/node": ["@types/node@24.12.2", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-A1sre26ke7HDIuY/M23nd9gfB+nrmhtYyMINbjI1zHJxYteKR6qSMX56FsmjMcDb3SMcjJg5BiRRgOCC/yBD0g=="],
+
+ "@types/fs-extra/@types/node": ["@types/node@24.12.2", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-A1sre26ke7HDIuY/M23nd9gfB+nrmhtYyMINbjI1zHJxYteKR6qSMX56FsmjMcDb3SMcjJg5BiRRgOCC/yBD0g=="],
"@types/jsdom/undici-types": ["undici-types@7.25.0", "", {}, "sha512-AXNgS1Byr27fTI+2bsPEkV9CxkT8H6xNyRI68b3TatlZo3RkzlqQBLL+w7SmGPVpokjHbcuNVQUWE7FRTg+LRA=="],
- "@types/node-fetch/@types/node": ["@types/node@25.6.0", "", { "dependencies": { "undici-types": "~7.19.0" } }, "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ=="],
+ "@types/keyv/@types/node": ["@types/node@24.12.2", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-A1sre26ke7HDIuY/M23nd9gfB+nrmhtYyMINbjI1zHJxYteKR6qSMX56FsmjMcDb3SMcjJg5BiRRgOCC/yBD0g=="],
+
+ "@types/plist/@types/node": ["@types/node@24.12.2", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-A1sre26ke7HDIuY/M23nd9gfB+nrmhtYyMINbjI1zHJxYteKR6qSMX56FsmjMcDb3SMcjJg5BiRRgOCC/yBD0g=="],
+
+ "@types/responselike/@types/node": ["@types/node@24.12.2", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-A1sre26ke7HDIuY/M23nd9gfB+nrmhtYyMINbjI1zHJxYteKR6qSMX56FsmjMcDb3SMcjJg5BiRRgOCC/yBD0g=="],
- "@types/yazl/@types/node": ["@types/node@25.6.0", "", { "dependencies": { "undici-types": "~7.19.0" } }, "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ=="],
+ "@types/ws/@types/node": ["@types/node@24.12.2", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-A1sre26ke7HDIuY/M23nd9gfB+nrmhtYyMINbjI1zHJxYteKR6qSMX56FsmjMcDb3SMcjJg5BiRRgOCC/yBD0g=="],
+
+ "@types/yauzl/@types/node": ["@types/node@24.12.2", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-A1sre26ke7HDIuY/M23nd9gfB+nrmhtYyMINbjI1zHJxYteKR6qSMX56FsmjMcDb3SMcjJg5BiRRgOCC/yBD0g=="],
"ajv-keywords/ajv": ["ajv@6.14.0", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw=="],
@@ -4440,12 +4452,8 @@
"ast-kit/@babel/parser": ["@babel/parser@8.0.0-rc.3", "", { "dependencies": { "@babel/types": "^8.0.0-rc.3" }, "bin": "./bin/babel-parser.js" }, "sha512-B20dvP3MfNc/XS5KKCHy/oyWl5IA6Cn9YjXRdDlCjNmUFrjvLXMNUfQq/QUy9fnG2gYkKKcrto2YaF9B32ToOQ=="],
- "buffer-image-size/@types/node": ["@types/node@25.6.0", "", { "dependencies": { "undici-types": "~7.19.0" } }, "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ=="],
-
"builder-util/fs-extra": ["fs-extra@10.1.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ=="],
- "bun-types/@types/node": ["@types/node@25.6.0", "", { "dependencies": { "undici-types": "~7.19.0" } }, "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ=="],
-
"cacache/glob": ["glob@10.5.0", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg=="],
"cacache/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="],
@@ -4484,6 +4492,8 @@
"dotenv-expand/dotenv": ["dotenv@16.6.1", "", {}, "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow=="],
+ "electron/@types/node": ["@types/node@24.12.2", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-A1sre26ke7HDIuY/M23nd9gfB+nrmhtYyMINbjI1zHJxYteKR6qSMX56FsmjMcDb3SMcjJg5BiRRgOCC/yBD0g=="],
+
"electron-builder/fs-extra": ["fs-extra@10.1.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ=="],
"electron-publish/fs-extra": ["fs-extra@10.1.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ=="],
@@ -4526,8 +4536,6 @@
"glob/minimatch": ["minimatch@3.1.5", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w=="],
- "happy-dom/@types/node": ["@types/node@25.6.0", "", { "dependencies": { "undici-types": "~7.19.0" } }, "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ=="],
-
"happy-dom/whatwg-mimetype": ["whatwg-mimetype@3.0.0", "", {}, "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q=="],
"hast-util-from-html/parse5": ["parse5@7.3.0", "", { "dependencies": { "entities": "^6.0.0" } }, "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw=="],
@@ -4618,8 +4626,6 @@
"prosemirror-trailing-node/escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="],
- "protobufjs/@types/node": ["@types/node@25.6.0", "", { "dependencies": { "undici-types": "~7.19.0" } }, "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ=="],
-
"proxy-addr/ipaddr.js": ["ipaddr.js@1.9.1", "", {}, "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="],
"proxy-agent/lru-cache": ["lru-cache@7.18.3", "", {}, "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA=="],
@@ -4838,9 +4844,11 @@
"@inkeep/cxkit-primitives/@radix-ui/react-tooltip/@radix-ui/react-visually-hidden": ["@radix-ui/react-visually-hidden@1.1.1", "", { "dependencies": { "@radix-ui/react-primitive": "2.0.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-vVfA2IZ9q/J+gEamvj761Oq1FpWgCDaNOOIfbPVp2MVPLEomUr5+Vf7kJGwQ24YxZSlQVar7Bes8kyTo5Dshpg=="],
- "@inkeep/open-knowledge-core/@types/node/undici-types": ["undici-types@7.19.2", "", {}, "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg=="],
+ "@inkeep/open-knowledge-desktop/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
- "@inkeep/open-knowledge-server/@types/yazl/@types/node": ["@types/node@25.6.0", "", { "dependencies": { "undici-types": "~7.19.0" } }, "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ=="],
+ "@inkeep/open-knowledge-docs/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
+
+ "@inkeep/open-knowledge/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
"@inquirer/confirm/@inquirer/core/@inquirer/ansi": ["@inquirer/ansi@1.0.2", "", {}, "sha512-S8qNSZiYzFd0wAcyG5AXCvUHC5Sr7xpZ9wZ2py9XR88jUz8wooStVx5M6dRzczbBWjic9NP7+rY0Xi7qqK/aMQ=="],
@@ -4858,8 +4866,6 @@
"@isaacs/cliui/wrap-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="],
- "@jest/types/@types/node/undici-types": ["undici-types@7.19.2", "", {}, "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg=="],
-
"@malept/flatpak-bundler/fs-extra/jsonfile": ["jsonfile@6.2.0", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg=="],
"@malept/flatpak-bundler/fs-extra/universalify": ["universalify@2.0.1", "", {}, "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw=="],
@@ -4902,11 +4908,21 @@
"@radix-ui/react-popover/@radix-ui/react-use-controllable-state/@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-jrBWOxZITuGcnjRCM2t2U5ZPkCLxD+Ym6DjfssS5haTj2iiak/DOb64JeN6OdLfLgptb6/e2kKR+ZuTrGoZTPA=="],
- "@types/jsdom/@types/node/undici-types": ["undici-types@7.19.2", "", {}, "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg=="],
+ "@types/busboy/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
+
+ "@types/cacheable-request/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
+
+ "@types/fs-extra/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
+
+ "@types/keyv/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
+
+ "@types/plist/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
+
+ "@types/responselike/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
- "@types/node-fetch/@types/node/undici-types": ["undici-types@7.19.2", "", {}, "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg=="],
+ "@types/ws/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
- "@types/yazl/@types/node/undici-types": ["undici-types@7.19.2", "", {}, "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg=="],
+ "@types/yauzl/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
"ajv-keywords/ajv/json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="],
@@ -4926,14 +4942,10 @@
"ast-kit/@babel/parser/@babel/types": ["@babel/types@8.0.0-rc.3", "", { "dependencies": { "@babel/helper-string-parser": "^8.0.0-rc.3", "@babel/helper-validator-identifier": "^8.0.0-rc.3" } }, "sha512-mOm5ZrYmphGfqVWoH5YYMTITb3cDXsFgmvFlvkvWDMsR9X8RFnt7a0Wb6yNIdoFsiMO9WjYLq+U/FMtqIYAF8Q=="],
- "buffer-image-size/@types/node/undici-types": ["undici-types@7.19.2", "", {}, "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg=="],
-
"builder-util/fs-extra/jsonfile": ["jsonfile@6.2.0", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg=="],
"builder-util/fs-extra/universalify": ["universalify@2.0.1", "", {}, "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw=="],
- "bun-types/@types/node/undici-types": ["undici-types@7.19.2", "", {}, "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg=="],
-
"cacache/glob/minimatch": ["minimatch@9.0.9", "", { "dependencies": { "brace-expansion": "^2.0.2" } }, "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg=="],
"cli-truncate/string-width/strip-ansi": ["strip-ansi@7.2.0", "", { "dependencies": { "ansi-regex": "^6.2.2" } }, "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w=="],
@@ -4962,6 +4974,8 @@
"electron-updater/fs-extra/universalify": ["universalify@2.0.1", "", {}, "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw=="],
+ "electron/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
+
"filelist/minimatch/brace-expansion": ["brace-expansion@2.1.0", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w=="],
"form-data/mime-types/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="],
@@ -5024,8 +5038,6 @@
"glob/minimatch/brace-expansion": ["brace-expansion@1.1.14", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g=="],
- "happy-dom/@types/node/undici-types": ["undici-types@7.19.2", "", {}, "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg=="],
-
"hast-util-from-html/parse5/entities": ["entities@6.0.1", "", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="],
"hast-util-raw/parse5/entities": ["entities@6.0.1", "", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="],
@@ -5062,8 +5074,6 @@
"prebuild-install/tar-fs/tar-stream": ["tar-stream@2.2.0", "", { "dependencies": { "bl": "^4.0.3", "end-of-stream": "^1.4.1", "fs-constants": "^1.0.0", "inherits": "^2.0.3", "readable-stream": "^3.1.1" } }, "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ=="],
- "protobufjs/@types/node/undici-types": ["undici-types@7.19.2", "", {}, "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg=="],
-
"puppeteer-core/chromium-bidi/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="],
"puppeteer/puppeteer-core/webdriver-bidi-protocol": ["webdriver-bidi-protocol@0.4.1", "", {}, "sha512-ARrjNjtWRRs2w4Tk7nqrf2gBI0QXWuOmMCx2hU+1jUt6d00MjMxURrhxhGbrsoiZKJrhTSTzbIrc554iKI10qw=="],
@@ -5254,8 +5264,6 @@
"@inkeep/cxkit-primitives/@radix-ui/react-tooltip/@radix-ui/react-use-controllable-state/@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.1.0", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw=="],
- "@inkeep/open-knowledge-server/@types/yazl/@types/node/undici-types": ["undici-types@7.19.2", "", {}, "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg=="],
-
"@opentelemetry/instrumentation-fetch/@opentelemetry/sdk-trace-web/@opentelemetry/sdk-trace-base/@opentelemetry/resources": ["@opentelemetry/resources@2.1.0", "", { "dependencies": { "@opentelemetry/core": "2.1.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-1CJjf3LCvoefUOgegxi8h6r4B/wLSzInyhGP2UmIBYNlo4Qk5CZ73e1eEyWmfXvFtm1ybkmfb2DqWvspsYLrWw=="],
"app-builder-lib/@electron/fuses/fs-extra/jsonfile": ["jsonfile@6.2.0", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg=="],
From 613bea1235d5c6932db5c3d421c61ba33ca8f36b Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sat, 27 Jun 2026 08:53:03 +0000
Subject: [PATCH 5/5] refactor: dedupe endpoint input normalization
---
.../app/src/components/settings/SearchSection.tsx | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/packages/app/src/components/settings/SearchSection.tsx b/packages/app/src/components/settings/SearchSection.tsx
index 013c9b71..95183e71 100644
--- a/packages/app/src/components/settings/SearchSection.tsx
+++ b/packages/app/src/components/settings/SearchSection.tsx
@@ -99,6 +99,11 @@ export function SearchSection() {
if (write(true)) setConfirmOpen(false);
}
+ function commitBaseUrlInput(input: HTMLInputElement): void {
+ const normalized = normalizeBaseUrl(input.value);
+ if (writeBaseUrl(input.value)) input.value = normalized;
+ }
+
const serverEnabled = status?.enabled ?? false;
const keyPresent = status?.keyPresent ?? false;
const ready = status?.ready ?? false;
@@ -180,15 +185,11 @@ export function SearchSection() {
key={configuredBaseUrl}
id="settings-search-base-url"
defaultValue={configuredBaseUrl}
- onBlur={(e) => {
- const normalized = normalizeBaseUrl(e.currentTarget.value);
- if (writeBaseUrl(e.currentTarget.value)) e.currentTarget.value = normalized;
- }}
+ onBlur={(e) => commitBaseUrlInput(e.currentTarget)}
onKeyDown={(e) => {
if (e.key === 'Enter') {
e.preventDefault();
- const normalized = normalizeBaseUrl(e.currentTarget.value);
- if (writeBaseUrl(e.currentTarget.value)) e.currentTarget.value = normalized;
+ commitBaseUrlInput(e.currentTarget);
}
}}
placeholder={DEFAULT_EMBEDDINGS_BASE_URL}