@dbx-tools/search 0.6.108 → 0.6.111
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +96 -110
- package/index.ts +6 -2
- package/lib/index.d.ts +6 -2
- package/lib/index.js +4 -1
- package/lib/src/client.d.ts +23 -43
- package/lib/src/client.js +51 -114
- package/lib/src/lakebase-plugin.d.ts +73 -0
- package/lib/src/lakebase-plugin.js +191 -0
- package/lib/src/lakebase.d.ts +6 -4
- package/lib/src/lakebase.js +45 -13
- package/lib/src/native.d.ts +18 -0
- package/lib/src/native.js +79 -0
- package/lib/src/plugin.d.ts +31 -59
- package/lib/src/plugin.js +63 -130
- package/lib/src/query.d.ts +1 -57
- package/lib/src/query.js +2 -93
- package/lib/src/runtime.d.ts +4 -11
- package/lib/src/runtime.js +3 -7
- package/lib/src/schema.d.ts +1 -1
- package/lib/src/tool.d.ts +1 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +9 -9
- package/src/client.ts +69 -137
- package/src/lakebase-plugin.ts +258 -0
- package/src/lakebase.ts +56 -15
- package/src/native.ts +117 -0
- package/src/plugin.ts +63 -148
- package/src/query.ts +1 -109
- package/src/runtime.ts +6 -16
package/lib/src/query.js
CHANGED
|
@@ -1,97 +1,6 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Translation between the browser-safe search contract and the Databricks
|
|
3
|
-
* Vector Search query API, kept in one place so the client, the tools, and the
|
|
4
|
-
* routes never hand-roll a `filters_json` string or unpack a `data_array` by
|
|
5
|
-
* hand.
|
|
6
|
-
*
|
|
7
|
-
* - {@link toQueryType} maps the friendly {@link SearchMode} onto the API's
|
|
8
|
-
* `query_type` (`HYBRID` / `ANN`). Keyword-only search rides on `ANN` with
|
|
9
|
-
* text but no vector, which Databricks answers with its BM25 path.
|
|
10
|
-
* - {@link compileFilter} turns the `{ column: value }` filter object (with
|
|
11
|
-
* optional operator maps like `{ ">=": 10 }`) into the `filters_json`
|
|
12
|
-
* string the API expects, so a caller never learns Databricks' filter
|
|
13
|
-
* spelling.
|
|
14
|
-
* - {@link toHits} unpacks the columnar `{ manifest, result }` response into
|
|
15
|
-
* `{ id, score, fields }` hits, pulling the score out of the reserved
|
|
16
|
-
* `__db_score` / `score` column and the id out of the primary-key column.
|
|
17
|
-
*
|
|
18
|
-
* @module
|
|
19
|
-
*/
|
|
1
|
+
/** Request-shape helpers for search extension write routes and tools. */
|
|
20
2
|
import { ValidationError } from "@databricks/appkit";
|
|
21
3
|
import { json, object } from "@dbx-tools/shared-core";
|
|
22
|
-
/** The column name Databricks Vector Search returns the relevance score under. */
|
|
23
|
-
const SCORE_COLUMN = "__db_score";
|
|
24
|
-
/** Map a {@link SearchMode} onto the serving API `query_type`. */
|
|
25
|
-
export function toQueryType(mode) {
|
|
26
|
-
return mode === "hybrid" ? "HYBRID" : "ANN";
|
|
27
|
-
}
|
|
28
|
-
/**
|
|
29
|
-
* Compile a `{ column: value }` filter object into the `filters_json` string
|
|
30
|
-
* the query API expects. A scalar becomes an equality; an array becomes an
|
|
31
|
-
* IN-style match; an operator map (`{ ">=": 10, "<": 20 }`) expands to the
|
|
32
|
-
* `column operator` keys Databricks uses. Returns `undefined` for an empty
|
|
33
|
-
* filter so the field is omitted rather than sent as `{}`.
|
|
34
|
-
*/
|
|
35
|
-
export function compileFilter(filter) {
|
|
36
|
-
if (!filter || Object.keys(filter).length === 0)
|
|
37
|
-
return undefined;
|
|
38
|
-
const compiled = {};
|
|
39
|
-
for (const [column, value] of Object.entries(filter)) {
|
|
40
|
-
if (object.isRecord(value)) {
|
|
41
|
-
for (const [op, operand] of Object.entries(value)) {
|
|
42
|
-
compiled[`${column} ${op}`] = operand;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
else {
|
|
46
|
-
compiled[column] = value;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
return JSON.stringify(compiled);
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* Unpack a columnar query response into {@link SearchHit}s. The manifest names
|
|
53
|
-
* the columns in order; each row is a positional array. The score comes from
|
|
54
|
-
* the reserved score column and the id from `primaryKey` (falling back to the
|
|
55
|
-
* first column when the key is unknown). The score column is stripped from
|
|
56
|
-
* `fields` so a hit's fields are just the document.
|
|
57
|
-
*/
|
|
58
|
-
export function toHits(response, primaryKey, indexName) {
|
|
59
|
-
const columns = (response.manifest?.columns ?? []).map((c) => c.name ?? "");
|
|
60
|
-
const rows = response.result?.data_array ?? [];
|
|
61
|
-
const scoreIdx = columns.indexOf(SCORE_COLUMN);
|
|
62
|
-
const keyIdx = primaryKey ? columns.indexOf(primaryKey) : -1;
|
|
63
|
-
return rows.map((row, rowIndex) => {
|
|
64
|
-
const fields = {};
|
|
65
|
-
columns.forEach((name, i) => {
|
|
66
|
-
if (i === scoreIdx || !name)
|
|
67
|
-
return;
|
|
68
|
-
fields[name] = row[i];
|
|
69
|
-
});
|
|
70
|
-
const scoreRaw = scoreIdx >= 0 ? Number(row[scoreIdx]) : NaN;
|
|
71
|
-
const idRaw = keyIdx >= 0 ? row[keyIdx] : primaryKey ? fields[primaryKey] : (row[0] ?? rowIndex);
|
|
72
|
-
return {
|
|
73
|
-
id: String(idRaw ?? rowIndex),
|
|
74
|
-
score: Number.isFinite(scoreRaw) ? scoreRaw : 0,
|
|
75
|
-
fields,
|
|
76
|
-
...(indexName ? { index: indexName } : {}),
|
|
77
|
-
};
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
/**
|
|
81
|
-
* The columns to request from an index for a search. When neither the request
|
|
82
|
-
* nor the index config names columns, the score column alone is requested and
|
|
83
|
-
* the primary key is appended so a hit always has an id. Callers that want the
|
|
84
|
-
* whole document should pass the index's own column list.
|
|
85
|
-
*/
|
|
86
|
-
export function toRequestColumns(requested, fallback, primaryKey) {
|
|
87
|
-
const base = requested && requested.length > 0 ? requested : (fallback ?? []);
|
|
88
|
-
const columns = new Set(base);
|
|
89
|
-
if (primaryKey)
|
|
90
|
-
columns.add(primaryKey);
|
|
91
|
-
if (columns.size === 0 && primaryKey)
|
|
92
|
-
columns.add(primaryKey);
|
|
93
|
-
return [...columns];
|
|
94
|
-
}
|
|
95
4
|
/**
|
|
96
5
|
* Parse a JSON document payload the model / a route supplied for a write.
|
|
97
6
|
* Accepts an already-parsed array/object or a JSON string, and always returns
|
|
@@ -106,4 +15,4 @@ export function toDocumentArray(input) {
|
|
|
106
15
|
const list = Array.isArray(value) ? value : [value];
|
|
107
16
|
return list.filter(object.isRecord);
|
|
108
17
|
}
|
|
109
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicXVlcnkuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvcXVlcnkudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQWtCRztBQUVILE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUNyRCxPQUFPLEVBQUUsSUFBSSxFQUFFLE1BQU0sRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBR3RELGtGQUFrRjtBQUNsRixNQUFNLFlBQVksR0FBRyxZQUFZLENBQUM7QUFFbEMsa0VBQWtFO0FBQ2xFLE1BQU0sVUFBVSxXQUFXLENBQUMsSUFBZ0I7SUFDMUMsT0FBTyxJQUFJLEtBQUssUUFBUSxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQztBQUM5QyxDQUFDO0FBRUQ7Ozs7OztHQU1HO0FBQ0gsTUFBTSxVQUFVLGFBQWEsQ0FBQyxNQUEyQztJQUN2RSxJQUFJLENBQUMsTUFBTSxJQUFJLE1BQU0sQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUMsTUFBTSxLQUFLLENBQUM7UUFBRSxPQUFPLFNBQVMsQ0FBQztJQUNsRSxNQUFNLFFBQVEsR0FBNEIsRUFBRSxDQUFDO0lBQzdDLEtBQUssTUFBTSxDQUFDLE1BQU0sRUFBRSxLQUFLLENBQUMsSUFBSSxNQUFNLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUM7UUFDckQsSUFBSSxNQUFNLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUM7WUFDM0IsS0FBSyxNQUFNLENBQUMsRUFBRSxFQUFFLE9BQU8sQ0FBQyxJQUFJLE1BQU0sQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQztnQkFDbEQsUUFBUSxDQUFDLEdBQUcsTUFBTSxJQUFJLEVBQUUsRUFBRSxDQUFDLEdBQUcsT0FBTyxDQUFDO1lBQ3hDLENBQUM7UUFDSCxDQUFDO2FBQU0sQ0FBQztZQUNOLFFBQVEsQ0FB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QUFDLENBQUM7QUFDdEIsQ0FBQztBQUVEOzs7OztHQUtHO0FBQ0gsTUFBTSxVQUFVLGVBQWUsQ0FBQyxLQUFjO0lBQzVDLE1BQU0sS0FBSyxHQUFHLE9BQU8sS0FBSyxLQUFLLFFBQVEsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxLQUFLLEVBQUUsU0FBUyxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQztJQUMvRSxJQUFJLEtBQUssS0FBSyxTQUFTLEVBQUUsQ0FBQztRQUN4QixNQUFNLElBQUksZUFBZSxDQUFDLG1EQUFtRCxDQUFDLENBQUM7SUFDakYsQ0FBQztJQUNELE1BQU0sSUFBSSxHQUFHLEtBQUssQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUNwRCxPQUFPLElBQUksQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxDQUFDO0FBQ3RDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIFRyYW5zbGF0aW9uIGJldHdlZW4gdGhlIGJyb3dzZXItc2FmZSBzZWFyY2ggY29udHJhY3QgYW5kIHRoZSBEYXRhYnJpY2tzXG4gKiBWZWN0b3IgU2VhcmNoIHF1ZXJ5IEFQSSwga2VwdCBpbiBvbmUgcGxhY2Ugc28gdGhlIGNsaWVudCwgdGhlIHRvb2xzLCBhbmQgdGhlXG4gKiByb3V0ZXMgbmV2ZXIgaGFuZC1yb2xsIGEgYGZpbHRlcnNfanNvbmAgc3RyaW5nIG9yIHVucGFjayBhIGBkYXRhX2FycmF5YCBieVxuICogaGFuZC5cbiAqXG4gKiAgIC0ge0BsaW5rIHRvUXVlcnlUeXBlfSBtYXBzIHRoZSBmcmllbmRseSB7QGxpbmsgU2VhcmNoTW9kZX0gb250byB0aGUgQVBJJ3NcbiAqICAgICBgcXVlcnlfdHlwZWAgKGBIWUJSSURgIC8gYEFOTmApLiBLZXl3b3JkLW9ubHkgc2VhcmNoIHJpZGVzIG9uIGBBTk5gIHdpdGhcbiAqICAgICB0ZXh0IGJ1dCBubyB2ZWN0b3IsIHdoaWNoIERhdGFicmlja3MgYW5zd2VycyB3aXRoIGl0cyBCTTI1IHBhdGguXG4gKiAgIC0ge0BsaW5rIGNvbXBpbGVGaWx0ZXJ9IHR1cm5zIHRoZSBgeyBjb2x1bW46IHZhbHVlIH1gIGZpbHRlciBvYmplY3QgKHdpdGhcbiAqICAgICBvcHRpb25hbCBvcGVyYXRvciBtYXBzIGxpa2UgYHsgXCI+PVwiOiAxMCB9YCkgaW50byB0aGUgYGZpbHRlcnNfanNvbmBcbiAqICAgICBzdHJpbmcgdGhlIEFQSSBleHBlY3RzLCBzbyBhIGNhbGxlciBuZXZlciBsZWFybnMgRGF0YWJyaWNrcycgZmlsdGVyXG4gKiAgICAgc3BlbGxpbmcuXG4gKiAgIC0ge0BsaW5rIHRvSGl0c30gdW5wYWNrcyB0aGUgY29sdW1uYXIgYHsgbWFuaWZlc3QsIHJlc3VsdCB9YCByZXNwb25zZSBpbnRvXG4gKiAgICAgYHsgaWQsIHNjb3JlLCBmaWVsZHMgfWAgaGl0cywgcHVsbGluZyB0aGUgc2NvcmUgb3V0IG9mIHRoZSByZXNlcnZlZFxuICogICAgIGBfX2RiX3Njb3JlYCAvIGBzY29yZWAgY29sdW1uIGFuZCB0aGUgaWQgb3V0IG9mIHRoZSBwcmltYXJ5LWtleSBjb2x1bW4uXG4gKlxuICogQG1vZHVsZVxuICovXG5cbmltcG9ydCB7IFZhbGlkYXRpb25FcnJvciB9IGZyb20gXCJAZGF0YWJyaWNrcy9hcHBraXRcIjtcbmltcG9ydCB7IGpzb24sIG9iamVjdCB9IGZyb20gXCJAZGJ4LXRvb2xzL3NoYXJlZC1jb3JlXCI7XG5pbXBvcnQgdHlwZSB7IFNlYXJjaEhpdCwgU2VhcmNoTW9kZSB9IGZyb20gXCJAZGJ4LXRvb2xzL3NoYXJlZC1zZWFyY2hcIjtcblxuLyoqIFRoZSBjb2x1bW4gbmFtZSBEYXRhYnJpY2tzIFZlY3RvciBTZWFyY2ggcmV0dXJucyB0aGUgcmVsZXZhbmNlIHNjb3JlIHVuZGVyLiAqL1xuY29uc3QgU0NPUkVfQ09MVU1OID0gXCJfX2RiX3Njb3JlXCI7XG5cbi8qKiBNYXAgYSB7QGxpbmsgU2VhcmNoTW9kZX0gb250byB0aGUgc2VydmluZyBBUEkgYHF1ZXJ5X3R5cGVgLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHRvUXVlcnlUeXBlKG1vZGU6IFNlYXJjaE1vZGUpOiBzdHJpbmcge1xuICByZXR1cm4gbW9kZSA9PT0gXCJoeWJyaWRcIiA/IFwiSFlCUklEXCIgOiBcIkFOTlwiO1xufVxuXG4vKipcbiAqIENvbXBpbGUgYSBgeyBjb2x1bW46IHZhbHVlIH1gIGZpbHRlciBvYmplY3QgaW50byB0aGUgYGZpbHRlcnNfanNvbmAgc3RyaW5nXG4gKiB0aGUgcXVlcnkgQVBJIGV4cGVjdHMuIEEgc2NhbGFyIGJlY29tZXMgYW4gZXF1YWxpdHk7IGFuIGFycmF5IGJlY29tZXMgYW5cbiAqIElOLXN0eWxlIG1hdGNoOyBhbiBvcGVyYXRvciBtYXAgKGB7IFwiPj1cIjogMTAsIFwiPFwiOiAyMCB9YCkgZXhwYW5kcyB0byB0aGVcbiAqIGBjb2x1bW4gb3BlcmF0b3JgIGtleXMgRGF0YWJyaWNrcyB1c2VzLiBSZXR1cm5zIGB1bmRlZmluZWRgIGZvciBhbiBlbXB0eVxuICogZmlsdGVyIHNvIHRoZSBmaWVsZCBpcyBvbWl0dGVkIHJhdGhlciB0aGFuIHNlbnQgYXMgYHt9YC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNvbXBpbGVGaWx0ZXIoZmlsdGVyOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiB8IHVuZGVmaW5lZCk6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gIGlmICghZmlsdGVyIHx8IE9iamVjdC5rZXlzKGZpbHRlcikubGVuZ3RoID09PSAwKSByZXR1cm4gdW5kZWZpbmVkO1xuICBjb25zdCBjb21waWxlZDogUmVjb3JkPHN0cmluZywgdW5rbm93bj4gPSB7fTtcbiAgZm9yIChjb25zdCBbY29sdW1uLCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMoZmlsdGVyKSkge1xuICAgIGlmIChvYmplY3QuaXNSZWNvcmQodmFsdWUpKSB7XG4gICAgICBmb3IgKGNvbnN0IFtvcCwgb3BlcmFuZF0gb2YgT2JqZWN0LmVudHJpZXModmFsdWUpKSB7XG4gICAgICAgIGNvbXBpbGVkW2Ake2NvbHVtbn0gJHtvcH1gXSA9IG9wZXJhbmQ7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIGNvbXBpbGVkW2NvbHVtbl0gPSB2YWx1ZTtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KGNvbXBpbGVkKTtcbn1cblxuLyoqIEEgbWluaW1hbCBzdHJ1Y3R1cmFsIHZpZXcgb2YgdGhlIFZlY3RvciBTZWFyY2ggcXVlcnkgcmVzcG9uc2UuICovXG5leHBvcnQgaW50ZXJmYWNlIFF1ZXJ5UmVzcG9uc2VMaWtlIHtcbiAgbWFuaWZlc3Q/OiB7IGNvbHVtbnM/OiBBcnJheTx7IG5hbWU/OiBzdHJpbmcgfT4gfTtcbiAgcmVzdWx0PzogeyBkYXRhX2FycmF5PzogQXJyYXk8QXJyYXk8dW5rbm93bj4+IH07XG4gIG5leHRfcGFnZV90b2tlbj86IHN0cmluZztcbn1cblxuLyoqXG4gKiBVbnBhY2sgYSBjb2x1bW5hciBxdWVyeSByZXNwb25zZSBpbnRvIHtAbGluayBTZWFyY2hIaXR9cy4gVGhlIG1hbmlmZXN0IG5hbWVzXG4gKiB0aGUgY29sdW1ucyBpbiBvcmRlcjsgZWFjaCByb3cgaXMgYSBwb3NpdGlvbmFsIGFycmF5LiBUaGUgc2NvcmUgY29tZXMgZnJvbVxuICogdGhlIHJlc2VydmVkIHNjb3JlIGNvbHVtbiBhbmQgdGhlIGlkIGZyb20gYHByaW1hcnlLZXlgIChmYWxsaW5nIGJhY2sgdG8gdGhlXG4gKiBmaXJzdCBjb2x1bW4gd2hlbiB0aGUga2V5IGlzIHVua25vd24pLiBUaGUgc2NvcmUgY29sdW1uIGlzIHN0cmlwcGVkIGZyb21cbiAqIGBmaWVsZHNgIHNvIGEgaGl0J3MgZmllbGRzIGFyZSBqdXN0IHRoZSBkb2N1bWVudC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHRvSGl0cyhcbiAgcmVzcG9uc2U6IFF1ZXJ5UmVzcG9uc2VMaWtlLFxuICBwcmltYXJ5S2V5OiBzdHJpbmcgfCB1bmRlZmluZWQsXG4gIGluZGV4TmFtZT86IHN0cmluZyxcbik6IFNlYXJjaEhpdFtdIHtcbiAgY29uc3QgY29sdW1ucyA9IChyZXNwb25zZS5tYW5pZmVzdD8uY29sdW1ucyA/PyBbXSkubWFwKChjKSA9PiBjLm5hbWUgPz8gXCJcIik7XG4gIGNvbnN0IHJvd3MgPSByZXNwb25zZS5yZXN1bHQ/LmRhdGFfYXJyYXkgPz8gW107XG4gIGNvbnN0IHNjb3JlSWR4ID0gY29sdW1ucy5pbmRleE9mKFNDT1JFX0NPTFVNTik7XG4gIGNvbnN0IGtleUlkeCA9IHByaW1hcnlLZXkgPyBjb2x1bW5zLmluZGV4T2YocHJpbWFyeUtleSkgOiAtMTtcbiAgcmV0dXJuIHJvd3MubWFwKChyb3csIHJvd0luZGV4KSA9PiB7XG4gICAgY29uc3QgZmllbGRzOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiA9IHt9O1xuICAgIGNvbHVtbnMuZm9yRWFjaCgobmFtZSwgaSkgPT4ge1xuICAgICAgaWYgKGkgPT09IHNjb3JlSWR4IHx8ICFuYW1lKSByZXR1cm47XG4gICAgICBmaWVsZHNbbmFtZV0gPSByb3dbaV07XG4gICAgfSk7XG4gICAgY29uc3Qgc2NvcmVSYXcgPSBzY29yZUlkeCA+PSAwID8gTnVtYmVyKHJvd1tzY29yZUlkeF0pIDogTmFOO1xuICAgIGNvbnN0IGlkUmF3ID1cbiAgICAgIGtleUlkeCA+PSAwID8gcm93W2tleUlkeF0gOiBwcmltYXJ5S2V5ID8gZmllbGRzW3ByaW1hcnlLZXldIDogKHJvd1swXSA/PyByb3dJbmRleCk7XG4gICAgcmV0dXJuIHtcbiAgICAgIGlkOiBTdHJpbmcoaWRSYXcgPz8gcm93SW5kZXgpLFxuICAgICAgc2NvcmU6IE51bWJlci5pc0Zpbml0ZShzY29yZVJhdykgPyBzY29yZVJhdyA6IDAsXG4gICAgICBmaWVsZHMsXG4gICAgICAuLi4oaW5kZXhOYW1lID8geyBpbmRleDogaW5kZXhOYW1lIH0gOiB7fSksXG4gICAgfTtcbiAgfSk7XG59XG5cbi8qKlxuICogVGhlIGNvbHVtbnMgdG8gcmVxdWVzdCBmcm9tIGFuIGluZGV4IGZvciBhIHNlYXJjaC4gV2hlbiBuZWl0aGVyIHRoZSByZXF1ZXN0XG4gKiBub3IgdGhlIGluZGV4IGNvbmZpZyBuYW1lcyBjb2x1bW5zLCB0aGUgc2NvcmUgY29sdW1uIGFsb25lIGlzIHJlcXVlc3RlZCBhbmRcbiAqIHRoZSBwcmltYXJ5IGtleSBpcyBhcHBlbmRlZCBzbyBhIGhpdCBhbHdheXMgaGFzIGFuIGlkLiBDYWxsZXJzIHRoYXQgd2FudCB0aGVcbiAqIHdob2xlIGRvY3VtZW50IHNob3VsZCBwYXNzIHRoZSBpbmRleCdzIG93biBjb2x1bW4gbGlzdC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHRvUmVxdWVzdENvbHVtbnMoXG4gIHJlcXVlc3RlZDogcmVhZG9ubHkgc3RyaW5nW10gfCB1bmRlZmluZWQsXG4gIGZhbGxiYWNrOiByZWFkb25seSBzdHJpbmdbXSB8IHVuZGVmaW5lZCxcbiAgcHJpbWFyeUtleTogc3RyaW5nIHwgdW5kZWZpbmVkLFxuKTogc3RyaW5nW10ge1xuICBjb25zdCBiYXNlID0gcmVxdWVzdGVkICYmIHJlcXVlc3RlZC5sZW5ndGggPiAwID8gcmVxdWVzdGVkIDogKGZhbGxiYWNrID8/IFtdKTtcbiAgY29uc3QgY29sdW1ucyA9IG5ldyBTZXQ8c3RyaW5nPihiYXNlKTtcbiAgaWYgKHByaW1hcnlLZXkpIGNvbHVtbnMuYWRkKHByaW1hcnlLZXkpO1xuICBpZiAoY29sdW1ucy5zaXplID09PSAwICYmIHByaW1hcnlLZXkpIGNvbHVtbnMuYWRkKHByaW1hcnlLZXkpO1xuICByZXR1cm4gWy4uLmNvbHVtbnNdO1xufVxuXG4vKipcbiAqIFBhcnNlIGEgSlNPTiBkb2N1bWVudCBwYXlsb2FkIHRoZSBtb2RlbCAvIGEgcm91dGUgc3VwcGxpZWQgZm9yIGEgd3JpdGUuXG4gKiBBY2NlcHRzIGFuIGFscmVhZHktcGFyc2VkIGFycmF5L29iamVjdCBvciBhIEpTT04gc3RyaW5nLCBhbmQgYWx3YXlzIHJldHVybnNcbiAqIGFuIGFycmF5IHNvIGEgc2luZ2xlIGRvY3VtZW50IGFuZCBhIGJhdGNoIGFyZSBoYW5kbGVkIHRoZSBzYW1lIHdheS4gVGhyb3dzIGFcbiAqIHtAbGluayBWYWxpZGF0aW9uRXJyb3J9IG9uIHVucGFyc2VhYmxlIGlucHV0IHNvIHRoZSBjYWxsZXIgY2FuIHN1cmZhY2UgaXQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB0b0RvY3VtZW50QXJyYXkoaW5wdXQ6IHVua25vd24pOiBBcnJheTxSZWNvcmQ8c3RyaW5nLCB1bmtub3duPj4ge1xuICBjb25zdCB2YWx1ZSA9IHR5cGVvZiBpbnB1dCA9PT0gXCJzdHJpbmdcIiA/IGpzb24ucGFyc2UoaW5wdXQsIHVuZGVmaW5lZCkgOiBpbnB1dDtcbiAgaWYgKHZhbHVlID09PSB1bmRlZmluZWQpIHtcbiAgICB0aHJvdyBuZXcgVmFsaWRhdGlvbkVycm9yKFwiZG9jdW1lbnRzIG11c3QgYmUgYSBKU09OIG9iamVjdCwgYXJyYXksIG9yIHN0cmluZ1wiKTtcbiAgfVxuICBjb25zdCBsaXN0ID0gQXJyYXkuaXNBcnJheSh2YWx1ZSkgPyB2YWx1ZSA6IFt2YWx1ZV07XG4gIHJldHVybiBsaXN0LmZpbHRlcihvYmplY3QuaXNSZWNvcmQpO1xufVxuIl19
|
|
18
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicXVlcnkuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvcXVlcnkudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEseUVBQXlFO0FBRXpFLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUNyRCxPQUFPLEVBQUUsSUFBSSxFQUFFLE1BQU0sRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBRXREOzs7OztHQUtHO0FBQ0gsTUFBTSxVQUFVLGVBQWUsQ0FBQyxLQUFjO0lBQzVDLE1BQU0sS0FBSyxHQUFHLE9BQU8sS0FBSyxLQUFLLFFBQVEsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxLQUFLLEVBQUUsU0FBUyxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQztJQUMvRSxJQUFJLEtBQUssS0FBSyxTQUFTLEVBQUUsQ0FBQztRQUN4QixNQUFNLElBQUksZUFBZSxDQUFDLG1EQUFtRCxDQUFDLENBQUM7SUFDakYsQ0FBQztJQUNELE1BQU0sSUFBSSxHQUFHLEtBQUssQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUNwRCxPQUFPLElBQUksQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxDQUFDO0FBQ3RDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKiogUmVxdWVzdC1zaGFwZSBoZWxwZXJzIGZvciBzZWFyY2ggZXh0ZW5zaW9uIHdyaXRlIHJvdXRlcyBhbmQgdG9vbHMuICovXG5cbmltcG9ydCB7IFZhbGlkYXRpb25FcnJvciB9IGZyb20gXCJAZGF0YWJyaWNrcy9hcHBraXRcIjtcbmltcG9ydCB7IGpzb24sIG9iamVjdCB9IGZyb20gXCJAZGJ4LXRvb2xzL3NoYXJlZC1jb3JlXCI7XG5cbi8qKlxuICogUGFyc2UgYSBKU09OIGRvY3VtZW50IHBheWxvYWQgdGhlIG1vZGVsIC8gYSByb3V0ZSBzdXBwbGllZCBmb3IgYSB3cml0ZS5cbiAqIEFjY2VwdHMgYW4gYWxyZWFkeS1wYXJzZWQgYXJyYXkvb2JqZWN0IG9yIGEgSlNPTiBzdHJpbmcsIGFuZCBhbHdheXMgcmV0dXJuc1xuICogYW4gYXJyYXkgc28gYSBzaW5nbGUgZG9jdW1lbnQgYW5kIGEgYmF0Y2ggYXJlIGhhbmRsZWQgdGhlIHNhbWUgd2F5LiBUaHJvd3MgYVxuICoge0BsaW5rIFZhbGlkYXRpb25FcnJvcn0gb24gdW5wYXJzZWFibGUgaW5wdXQgc28gdGhlIGNhbGxlciBjYW4gc3VyZmFjZSBpdC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHRvRG9jdW1lbnRBcnJheShpbnB1dDogdW5rbm93bik6IEFycmF5PFJlY29yZDxzdHJpbmcsIHVua25vd24+PiB7XG4gIGNvbnN0IHZhbHVlID0gdHlwZW9mIGlucHV0ID09PSBcInN0cmluZ1wiID8ganNvbi5wYXJzZShpbnB1dCwgdW5kZWZpbmVkKSA6IGlucHV0O1xuICBpZiAodmFsdWUgPT09IHVuZGVmaW5lZCkge1xuICAgIHRocm93IG5ldyBWYWxpZGF0aW9uRXJyb3IoXCJkb2N1bWVudHMgbXVzdCBiZSBhIEpTT04gb2JqZWN0LCBhcnJheSwgb3Igc3RyaW5nXCIpO1xuICB9XG4gIGNvbnN0IGxpc3QgPSBBcnJheS5pc0FycmF5KHZhbHVlKSA/IHZhbHVlIDogW3ZhbHVlXTtcbiAgcmV0dXJuIGxpc3QuZmlsdGVyKG9iamVjdC5pc1JlY29yZCk7XG59XG4iXX0=
|
package/lib/src/runtime.d.ts
CHANGED
|
@@ -7,25 +7,18 @@
|
|
|
7
7
|
*
|
|
8
8
|
* @module
|
|
9
9
|
*/
|
|
10
|
-
import { SearchClient } from "./client.ts";
|
|
10
|
+
import { SearchClient, type SearchReadBackend } from "./client.ts";
|
|
11
11
|
import { type SearchPluginConfig, type ResolvedSearchConfig } from "./config.ts";
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* How the runtime is built. `lakebase` (when present) is the Postgres full-text
|
|
15
|
-
* FALLBACK backend the plugin wires up when no Vector Search endpoint is
|
|
16
|
-
* configured but the AppKit `lakebase` plugin is registered. Every read/write
|
|
17
|
-
* returns the same shape either way.
|
|
18
|
-
*/
|
|
12
|
+
/** Configuration and provider used to build the shared extension runtime. */
|
|
19
13
|
export interface SearchRuntimeOptions {
|
|
20
14
|
config?: SearchPluginConfig;
|
|
21
|
-
|
|
15
|
+
readBackend?: SearchReadBackend;
|
|
22
16
|
}
|
|
23
17
|
/** The shared resolved config plus the client reads run through. */
|
|
24
18
|
export interface SearchRuntime {
|
|
25
19
|
config: ResolvedSearchConfig;
|
|
26
20
|
client: SearchClient;
|
|
27
|
-
|
|
28
|
-
lakebase?: LakebaseSearchBackend;
|
|
21
|
+
readBackend?: SearchReadBackend;
|
|
29
22
|
}
|
|
30
23
|
/**
|
|
31
24
|
* Return the shared runtime, building it on first use from the supplied config
|
package/lib/src/runtime.js
CHANGED
|
@@ -19,20 +19,16 @@ let runtime;
|
|
|
19
19
|
export function getSearchRuntime(options) {
|
|
20
20
|
if (!runtime) {
|
|
21
21
|
const config = resolveSearchConfig(options?.config);
|
|
22
|
-
const lakebase = options?.lakebase;
|
|
23
22
|
runtime = {
|
|
24
23
|
config,
|
|
25
|
-
client: createSearchClient(config, undefined,
|
|
26
|
-
...(
|
|
24
|
+
client: createSearchClient(config, undefined, options?.readBackend),
|
|
25
|
+
...(options?.readBackend ? { readBackend: options.readBackend } : {}),
|
|
27
26
|
};
|
|
28
27
|
}
|
|
29
28
|
return runtime;
|
|
30
29
|
}
|
|
31
30
|
/** Drop the memoized runtime so the next {@link getSearchRuntime} rebuilds it. */
|
|
32
31
|
export function resetSearchRuntime() {
|
|
33
|
-
const backend = runtime?.lakebase;
|
|
34
32
|
runtime = undefined;
|
|
35
|
-
if (backend)
|
|
36
|
-
void backend.close();
|
|
37
33
|
}
|
|
38
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
34
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicnVudGltZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9ydW50aW1lLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7OztHQVFHO0FBRUgsT0FBTyxFQUFFLGtCQUFrQixFQUF3QyxNQUFNLGFBQWEsQ0FBQztBQUN2RixPQUFPLEVBQ0wsbUJBQW1CLEdBR3BCLE1BQU0sYUFBYSxDQUFDO0FBZXJCLElBQUksT0FBa0MsQ0FBQztBQUV2Qzs7Ozs7R0FLRztBQUNILE1BQU0sVUFBVSxnQkFBZ0IsQ0FBQyxPQUE4QjtJQUM3RCxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUM7UUFDYixNQUFNLE1BQU0sR0FBRyxtQkFBbUIsQ0FBQyxPQUFPLEVBQUUsTUFBTSxDQUFDLENBQUM7UUFDcEQsT0FBTyxHQUFHO1lBQ1IsTUFBTTtZQUNOLE1BQU0sRUFBRSxrQkFBa0IsQ0FBQyxNQUFNLEVBQUUsU0FBUyxFQUFFLE9BQU8sRUFBRSxXQUFXLENBQUM7WUFDbkUsR0FBRyxDQUFDLE9BQU8sRUFBRSxXQUFXLENBQUMsQ0FBQyxDQUFDLEVBQUUsV0FBVyxFQUFFLE9BQU8sQ0FBQyxXQUFXLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO1NBQ3RFLENBQUM7SUFDSixDQUFDO0lBQ0QsT0FBTyxPQUFPLENBQUM7QUFDakIsQ0FBQztBQUVELGtGQUFrRjtBQUNsRixNQUFNLFVBQVUsa0JBQWtCO0lBQ2hDLE9BQU8sR0FBRyxTQUFTLENBQUM7QUFDdEIsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogVGhlIHNoYXJlZCBBSSBTZWFyY2ggcnVudGltZTogdGhlIHJlc29sdmVkIGNvbmZpZyBwbHVzIGEgc2luZ2xlXG4gKiB7QGxpbmsgU2VhcmNoQ2xpZW50fSBpbnN0YW5jZSB0aGUgcGx1Z2luLCB0aGUgTWFzdHJhIHRvb2xzLCBhbmQgdGhlIHJvdXRlc1xuICogYWxsIHJlYWQuIE1pcnJvcnMgdGhlIHdlYi1zZWFyY2ggLyBlbWFpbCBydW50aW1lIHBhdHRlcm4gLSB0aGUgcGx1Z2luIHByaW1lc1xuICogaXQgZnJvbSBpdHMgY29uZmlnIGF0IHNldHVwLCBhbmQgZXZlcnl0aGluZyBlbHNlIHJlYWRzIHRoZSBzYW1lIGluc3RhbmNlIHNvXG4gKiBhIHRvb2wgaW52b2tlZCBvdXRzaWRlIHRoZSBhZ2VudCBzdGlsbCBzZWVzIHRoZSBkZXBsb3ltZW50J3MgY29uZmlnLlxuICpcbiAqIEBtb2R1bGVcbiAqL1xuXG5pbXBvcnQgeyBjcmVhdGVTZWFyY2hDbGllbnQsIFNlYXJjaENsaWVudCwgdHlwZSBTZWFyY2hSZWFkQmFja2VuZCB9IGZyb20gXCIuL2NsaWVudC50c1wiO1xuaW1wb3J0IHtcbiAgcmVzb2x2ZVNlYXJjaENvbmZpZyxcbiAgdHlwZSBTZWFyY2hQbHVnaW5Db25maWcsXG4gIHR5cGUgUmVzb2x2ZWRTZWFyY2hDb25maWcsXG59IGZyb20gXCIuL2NvbmZpZy50c1wiO1xuXG4vKiogQ29uZmlndXJhdGlvbiBhbmQgcHJvdmlkZXIgdXNlZCB0byBidWlsZCB0aGUgc2hhcmVkIGV4dGVuc2lvbiBydW50aW1lLiAqL1xuZXhwb3J0IGludGVyZmFjZSBTZWFyY2hSdW50aW1lT3B0aW9ucyB7XG4gIGNvbmZpZz86IFNlYXJjaFBsdWdpbkNvbmZpZztcbiAgcmVhZEJhY2tlbmQ/OiBTZWFyY2hSZWFkQmFja2VuZDtcbn1cblxuLyoqIFRoZSBzaGFyZWQgcmVzb2x2ZWQgY29uZmlnIHBsdXMgdGhlIGNsaWVudCByZWFkcyBydW4gdGhyb3VnaC4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgU2VhcmNoUnVudGltZSB7XG4gIGNvbmZpZzogUmVzb2x2ZWRTZWFyY2hDb25maWc7XG4gIGNsaWVudDogU2VhcmNoQ2xpZW50O1xuICByZWFkQmFja2VuZD86IFNlYXJjaFJlYWRCYWNrZW5kO1xufVxuXG5sZXQgcnVudGltZTogU2VhcmNoUnVudGltZSB8IHVuZGVmaW5lZDtcblxuLyoqXG4gKiBSZXR1cm4gdGhlIHNoYXJlZCBydW50aW1lLCBidWlsZGluZyBpdCBvbiBmaXJzdCB1c2UgZnJvbSB0aGUgc3VwcGxpZWQgY29uZmlnXG4gKiBsYXllcmVkIG92ZXIgZW52aXJvbm1lbnQgZGVmYXVsdHMuIE92ZXJyaWRlcyBhcmUgb25seSByZWFkIHdoZW4gdGhlIHJ1bnRpbWVcbiAqIGlzIGZpcnN0IGNyZWF0ZWQsIHNvIHByaW1lIGl0IGZyb20gdGhlIHBsdWdpbidzIGNvbmZpZyBhdCBzZXR1cDsgc3Vic2VxdWVudFxuICogY2FsbHMgcGFzcyBub3RoaW5nIGFuZCBnZXQgdGhlIHNhbWUgaW5zdGFuY2UuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRTZWFyY2hSdW50aW1lKG9wdGlvbnM/OiBTZWFyY2hSdW50aW1lT3B0aW9ucyk6IFNlYXJjaFJ1bnRpbWUge1xuICBpZiAoIXJ1bnRpbWUpIHtcbiAgICBjb25zdCBjb25maWcgPSByZXNvbHZlU2VhcmNoQ29uZmlnKG9wdGlvbnM/LmNvbmZpZyk7XG4gICAgcnVudGltZSA9IHtcbiAgICAgIGNvbmZpZyxcbiAgICAgIGNsaWVudDogY3JlYXRlU2VhcmNoQ2xpZW50KGNvbmZpZywgdW5kZWZpbmVkLCBvcHRpb25zPy5yZWFkQmFja2VuZCksXG4gICAgICAuLi4ob3B0aW9ucz8ucmVhZEJhY2tlbmQgPyB7IHJlYWRCYWNrZW5kOiBvcHRpb25zLnJlYWRCYWNrZW5kIH0gOiB7fSksXG4gICAgfTtcbiAgfVxuICByZXR1cm4gcnVudGltZTtcbn1cblxuLyoqIERyb3AgdGhlIG1lbW9pemVkIHJ1bnRpbWUgc28gdGhlIG5leHQge0BsaW5rIGdldFNlYXJjaFJ1bnRpbWV9IHJlYnVpbGRzIGl0LiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlc2V0U2VhcmNoUnVudGltZSgpOiB2b2lkIHtcbiAgcnVudGltZSA9IHVuZGVmaW5lZDtcbn1cbiJdfQ==
|
package/lib/src/schema.d.ts
CHANGED
|
@@ -27,7 +27,7 @@ export declare const searchToolSchema: import("zod").ZodObject<{
|
|
|
27
27
|
keyword: "keyword";
|
|
28
28
|
}>>;
|
|
29
29
|
columns: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString>>;
|
|
30
|
-
filter: import("zod").ZodOptional<import("zod").ZodRecord<import("zod").ZodString, import("zod").
|
|
30
|
+
filter: import("zod").ZodOptional<import("zod").ZodRecord<import("zod").ZodString, import("zod").ZodUnion<readonly [import("zod").ZodString, import("zod").ZodNumber, import("zod").ZodBoolean, import("zod").ZodArray<import("zod").ZodUnion<readonly [import("zod").ZodString, import("zod").ZodNumber]>>]>>>;
|
|
31
31
|
scoreThreshold: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
32
32
|
}, import("zod/v4/core").$strip>;
|
|
33
33
|
/** Schema for the `universal_search` tool input. */
|
package/lib/src/tool.d.ts
CHANGED
|
@@ -39,7 +39,7 @@ export declare function searchTool(options?: SearchToolOptions): import("@mastra
|
|
|
39
39
|
limit?: number | undefined;
|
|
40
40
|
mode?: "hybrid" | "vector" | "keyword" | undefined;
|
|
41
41
|
columns?: string[] | undefined;
|
|
42
|
-
filter?: Record<string,
|
|
42
|
+
filter?: Record<string, string | number | boolean | (string | number)[]> | undefined;
|
|
43
43
|
scoreThreshold?: number | undefined;
|
|
44
44
|
}, {
|
|
45
45
|
query: string;
|
package/lib/tsconfig.tsbuildinfo
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"root":["../src/client.ts","../src/config.ts","../src/index-tools.ts","../src/lakebase.ts","../src/plugin.ts","../src/query.ts","../src/runtime.ts","../src/schema.ts","../src/tool.ts","../index.ts"],"version":"5.9.3"}
|
|
1
|
+
{"root":["../src/client.ts","../src/config.ts","../src/index-tools.ts","../src/lakebase-plugin.ts","../src/lakebase.ts","../src/native.ts","../src/plugin.ts","../src/query.ts","../src/runtime.ts","../src/schema.ts","../src/tool.ts","../index.ts"],"version":"5.9.3"}
|
package/package.json
CHANGED
|
@@ -26,15 +26,15 @@
|
|
|
26
26
|
"typescript": "^5.9.3"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@databricks/appkit": "^0.
|
|
29
|
+
"@databricks/appkit": "^0.60.0",
|
|
30
30
|
"@databricks/sdk-experimental": "^0.17.0",
|
|
31
|
-
"@dbx-tools/appkit": "0.6.
|
|
32
|
-
"@dbx-tools/core": "0.6.
|
|
33
|
-
"@dbx-tools/model": "0.6.
|
|
34
|
-
"@dbx-tools/shared-core": "0.6.
|
|
35
|
-
"@dbx-tools/shared-model": "0.6.
|
|
36
|
-
"@dbx-tools/shared-search": "0.6.
|
|
37
|
-
"@mastra/core": "
|
|
31
|
+
"@dbx-tools/appkit": "0.6.111",
|
|
32
|
+
"@dbx-tools/core": "0.6.111",
|
|
33
|
+
"@dbx-tools/model": "0.6.111",
|
|
34
|
+
"@dbx-tools/shared-core": "0.6.111",
|
|
35
|
+
"@dbx-tools/shared-model": "0.6.111",
|
|
36
|
+
"@dbx-tools/shared-search": "0.6.111",
|
|
37
|
+
"@mastra/core": "1.47.0",
|
|
38
38
|
"pg": "^8.22.0",
|
|
39
39
|
"zod": "4.3.6"
|
|
40
40
|
},
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"./package.json": "./package.json"
|
|
53
53
|
}
|
|
54
54
|
},
|
|
55
|
-
"version": "0.6.
|
|
55
|
+
"version": "0.6.111",
|
|
56
56
|
"types": "./lib/index.d.ts",
|
|
57
57
|
"type": "module",
|
|
58
58
|
"exports": {
|
package/src/client.ts
CHANGED
|
@@ -1,25 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* query_type, num_results, filters_json })` is powerful but verbose, and the
|
|
6
|
-
* response is columnar. This client hides all of that behind two objects:
|
|
7
|
-
*
|
|
8
|
-
* ```ts
|
|
9
|
-
* const client = createSearchClient();
|
|
10
|
-
* const index = client.index("main.support.docs");
|
|
11
|
-
* const { hits } = await index.search("reset my password", { limit: 5 });
|
|
12
|
-
* await index.addDocuments([{ id: "42", title: "Reset", body: "..." }]);
|
|
13
|
-
* ```
|
|
2
|
+
* Search extension client. Reads delegate to the registered AppKit-compatible
|
|
3
|
+
* `aiSearch` provider; this module owns federated fan-out and the Vector Search
|
|
4
|
+
* lifecycle APIs AppKit does not expose.
|
|
14
5
|
*
|
|
15
6
|
* `client.search(query, opts)` searches the default index; `client.index(name)`
|
|
16
7
|
* returns a handle bound to one index; `client.universalSearch(query)` fans a
|
|
17
8
|
* query across several indexes and merges the results (Meilisearch's federated
|
|
18
9
|
* / multi-search, the "universal search" the caller asked for). Everything is
|
|
19
|
-
* async and cancellable
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
10
|
+
* async and cancellable and returns the browser-safe shapes from
|
|
11
|
+
* `@dbx-tools/shared-search`. Lifecycle methods cross AppKit's explicit legacy
|
|
12
|
+
* client handoff because the public facade does not yet expose index creation,
|
|
13
|
+
* sync, or deletion.
|
|
23
14
|
*
|
|
24
15
|
* Autocomplete is just a search with a small `limit` and the raw query text -
|
|
25
16
|
* hybrid mode already prefix-matches, so no separate endpoint is needed; the
|
|
@@ -38,6 +29,7 @@ import type {
|
|
|
38
29
|
SearchDocument,
|
|
39
30
|
SearchHit,
|
|
40
31
|
SearchMode,
|
|
32
|
+
SearchRequest,
|
|
41
33
|
SearchResult,
|
|
42
34
|
UpsertResult,
|
|
43
35
|
} from "@dbx-tools/shared-search";
|
|
@@ -45,22 +37,25 @@ import {
|
|
|
45
37
|
DEFAULT_MODE,
|
|
46
38
|
DEFAULT_PAGE_SIZE,
|
|
47
39
|
DEFAULT_TIMEOUT_MS,
|
|
48
|
-
indexConfigFor,
|
|
49
40
|
resolveIndexName,
|
|
50
41
|
type ResolvedSearchConfig,
|
|
51
42
|
} from "./config.ts";
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
compileFilter,
|
|
55
|
-
toHits,
|
|
56
|
-
toQueryType,
|
|
57
|
-
toRequestColumns,
|
|
58
|
-
type QueryResponseLike,
|
|
59
|
-
} from "./query.ts";
|
|
60
|
-
|
|
61
|
-
type WorkspaceClientLike = appkit.WorkspaceClientLike;
|
|
43
|
+
|
|
44
|
+
type WorkspaceClientLike = ReturnType<appkit.WorkspaceClientLike["toLegacyWorkspaceClient"]>;
|
|
62
45
|
const logger = log.logger("search/client");
|
|
63
46
|
|
|
47
|
+
/** Query backend used when AppKit owns the Vector Search execution path. */
|
|
48
|
+
export interface SearchReadBackend {
|
|
49
|
+
/** Whether Vector Search lifecycle methods are valid for this provider. */
|
|
50
|
+
supportsLifecycle: boolean;
|
|
51
|
+
search(index: string, query: string, options?: SearchOptions): Promise<SearchResult>;
|
|
52
|
+
addDocuments?(
|
|
53
|
+
index: string,
|
|
54
|
+
documents: SearchDocument[],
|
|
55
|
+
signal?: AbortSignal,
|
|
56
|
+
): Promise<UpsertResult>;
|
|
57
|
+
}
|
|
58
|
+
|
|
64
59
|
/** Options accepted by a single-index search. */
|
|
65
60
|
export interface SearchOptions {
|
|
66
61
|
/** Maximum hits to return. Defaults to the configured page size. */
|
|
@@ -69,8 +64,8 @@ export interface SearchOptions {
|
|
|
69
64
|
mode?: SearchMode;
|
|
70
65
|
/** Columns to return per hit. Defaults to the index's configured columns. */
|
|
71
66
|
columns?: readonly string[];
|
|
72
|
-
/**
|
|
73
|
-
filter?:
|
|
67
|
+
/** AppKit AI Search scalar/array filters. */
|
|
68
|
+
filter?: SearchRequest["filter"];
|
|
74
69
|
/** Drop hits below this score. */
|
|
75
70
|
scoreThreshold?: number;
|
|
76
71
|
/** External cancellation. */
|
|
@@ -247,20 +242,9 @@ export class SearchClient {
|
|
|
247
242
|
allowWrite: false,
|
|
248
243
|
},
|
|
249
244
|
private readonly workspaceClientFactory: () => WorkspaceClientLike = defaultWorkspaceClient,
|
|
250
|
-
|
|
251
|
-
* Optional Lakebase full-text FALLBACK backend. Present only when no Vector
|
|
252
|
-
* Search endpoint is configured but a Lakebase pool is available; when set,
|
|
253
|
-
* search / provision / write operations delegate to it and return the exact
|
|
254
|
-
* same shapes, so nothing downstream can tell which backend answered.
|
|
255
|
-
*/
|
|
256
|
-
private readonly lakebase?: LakebaseSearchBackend,
|
|
245
|
+
private readonly readBackend?: SearchReadBackend,
|
|
257
246
|
) {}
|
|
258
247
|
|
|
259
|
-
/** True when this client is answering out of the Lakebase fallback backend. */
|
|
260
|
-
get usesLakebase(): boolean {
|
|
261
|
-
return this.lakebase !== undefined;
|
|
262
|
-
}
|
|
263
|
-
|
|
264
248
|
/** A handle bound to one index (by full UC name or configured alias). */
|
|
265
249
|
index(reference: string): SearchIndex {
|
|
266
250
|
const name = resolveIndexName(this.config, reference) ?? reference;
|
|
@@ -282,68 +266,16 @@ export class SearchClient {
|
|
|
282
266
|
context: { operation: "search" },
|
|
283
267
|
});
|
|
284
268
|
}
|
|
285
|
-
if (this.
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
...(options.signal ? { signal: options.signal } : {}),
|
|
290
|
-
});
|
|
291
|
-
}
|
|
292
|
-
const known = indexConfigFor(this.config, name);
|
|
293
|
-
const primaryKey = known?.primaryKey;
|
|
294
|
-
const columns = toRequestColumns(
|
|
295
|
-
options.columns,
|
|
296
|
-
known?.columns ?? this.config.columns,
|
|
297
|
-
primaryKey,
|
|
298
|
-
);
|
|
299
|
-
const mode = options.mode ?? this.config.mode;
|
|
300
|
-
const limit = options.limit ?? this.config.pageSize;
|
|
301
|
-
|
|
302
|
-
// Databricks only manages embeddings for Delta Sync indexes, so a query
|
|
303
|
-
// against a DIRECT_ACCESS index must carry a query VECTOR, not text. Embed
|
|
304
|
-
// the query client-side in that case (the index type is cached after the
|
|
305
|
-
// first lookup so this costs one extra call per index, not per search).
|
|
306
|
-
const directAccess = await this.isDirectAccess(name, options.signal);
|
|
307
|
-
const queryVector = directAccess
|
|
308
|
-
? (await this.embed([text], this.config.embeddingModel, options.signal))[0]
|
|
309
|
-
: undefined;
|
|
310
|
-
|
|
311
|
-
const response = await this.withClient("search", options.signal, async (client, context) => {
|
|
312
|
-
return client.vectorSearchIndexes.queryIndex(
|
|
313
|
-
{
|
|
314
|
-
index_name: name,
|
|
315
|
-
columns,
|
|
316
|
-
...(queryVector ? { query_vector: queryVector } : { query_text: text }),
|
|
317
|
-
query_type: toQueryType(mode),
|
|
318
|
-
num_results: limit,
|
|
319
|
-
...(compileFilter(options.filter) ? { filters_json: compileFilter(options.filter) } : {}),
|
|
320
|
-
...(options.scoreThreshold !== undefined
|
|
321
|
-
? { score_threshold: options.scoreThreshold }
|
|
322
|
-
: {}),
|
|
323
|
-
},
|
|
324
|
-
context,
|
|
269
|
+
if (!this.readBackend) {
|
|
270
|
+
throw new ExecutionError(
|
|
271
|
+
"search: no AI Search provider registered; add aiSearch() or lakebaseAiSearch()",
|
|
272
|
+
{ context: { operation: "search" } },
|
|
325
273
|
);
|
|
326
|
-
});
|
|
327
|
-
|
|
328
|
-
const hits = toHits(response as QueryResponseLike, primaryKey);
|
|
329
|
-
return { query: text, index: name, hits, count: hits.length };
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
/** Cache of index-name -> is-DIRECT_ACCESS, so a search embeds its query only when needed. */
|
|
333
|
-
private readonly directAccessCache = new Map<string, boolean>();
|
|
334
|
-
|
|
335
|
-
/** Whether an index is DIRECT_ACCESS (memoized); a lookup failure assumes Delta Sync. */
|
|
336
|
-
private async isDirectAccess(name: string, signal?: AbortSignal): Promise<boolean> {
|
|
337
|
-
const cached = this.directAccessCache.get(name);
|
|
338
|
-
if (cached !== undefined) return cached;
|
|
339
|
-
try {
|
|
340
|
-
const info = await this.getIndex(name, signal);
|
|
341
|
-
const value = info.directAccess ?? false;
|
|
342
|
-
this.directAccessCache.set(name, value);
|
|
343
|
-
return value;
|
|
344
|
-
} catch {
|
|
345
|
-
return false;
|
|
346
274
|
}
|
|
275
|
+
return this.readBackend.search(name, text, {
|
|
276
|
+
...options,
|
|
277
|
+
limit: options.limit ?? this.config.pageSize,
|
|
278
|
+
});
|
|
347
279
|
}
|
|
348
280
|
|
|
349
281
|
/**
|
|
@@ -405,8 +337,18 @@ export class SearchClient {
|
|
|
405
337
|
return name;
|
|
406
338
|
}
|
|
407
339
|
|
|
340
|
+
/** Reject Vector Search lifecycle calls against a non-Vector provider. */
|
|
341
|
+
private requireLifecycle(operation: string): void {
|
|
342
|
+
if (this.readBackend && !this.readBackend.supportsLifecycle) {
|
|
343
|
+
throw new ExecutionError(`search: the registered provider does not support ${operation}`, {
|
|
344
|
+
context: { operation },
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
408
349
|
/** Fetch an index's live definition. */
|
|
409
350
|
async getIndex(reference: string, signal?: AbortSignal): Promise<IndexInfo> {
|
|
351
|
+
this.requireLifecycle("getIndex");
|
|
410
352
|
const name = this.requireIndexName(reference, "getIndex");
|
|
411
353
|
const index = await this.withClient("getIndex", signal, (client, context) =>
|
|
412
354
|
client.vectorSearchIndexes.getIndex({ index_name: name }, context),
|
|
@@ -446,14 +388,10 @@ export class SearchClient {
|
|
|
446
388
|
signal?: AbortSignal,
|
|
447
389
|
): Promise<UpsertResult> {
|
|
448
390
|
const name = this.requireIndexName(reference, "addDocuments");
|
|
449
|
-
if (this.
|
|
450
|
-
return this.
|
|
451
|
-
name,
|
|
452
|
-
documents,
|
|
453
|
-
this.config.ensureOnSetup?.textColumn ?? "text",
|
|
454
|
-
signal,
|
|
455
|
-
);
|
|
391
|
+
if (this.readBackend?.addDocuments) {
|
|
392
|
+
return this.readBackend.addDocuments(name, documents, signal);
|
|
456
393
|
}
|
|
394
|
+
this.requireLifecycle("addDocuments");
|
|
457
395
|
await this.withClient("addDocuments", signal, (client, context) =>
|
|
458
396
|
client.vectorSearchIndexes.upsertDataVectorIndex(
|
|
459
397
|
{ index_name: name, inputs_json: JSON.stringify(documents) },
|
|
@@ -469,10 +407,8 @@ export class SearchClient {
|
|
|
469
407
|
ids: Array<string | number>,
|
|
470
408
|
signal?: AbortSignal,
|
|
471
409
|
): Promise<UpsertResult> {
|
|
410
|
+
this.requireLifecycle("deleteDocuments");
|
|
472
411
|
const name = this.requireIndexName(reference, "deleteDocuments");
|
|
473
|
-
if (this.lakebase) {
|
|
474
|
-
return this.lakebase.deleteDocuments(name, ids, signal);
|
|
475
|
-
}
|
|
476
412
|
await this.withClient("deleteDocuments", signal, (client, context) =>
|
|
477
413
|
client.vectorSearchIndexes.deleteDataVectorIndex(
|
|
478
414
|
{ index_name: name, primary_keys: ids.map(String) },
|
|
@@ -493,14 +429,15 @@ export class SearchClient {
|
|
|
493
429
|
// is used verbatim - no need to fetch and fuzzy-match the live catalogue.
|
|
494
430
|
// A genuinely loose name (e.g. "gte large") still resolves against it.
|
|
495
431
|
if (explicit && !/\s/.test(explicit)) return explicit;
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
432
|
+
signal?.throwIfAborted();
|
|
433
|
+
const client = defaultAppKitWorkspaceClient();
|
|
434
|
+
const host = (await client.config.getHost()).toString();
|
|
435
|
+
const endpoints = await serving.listServingEndpoints(client, host);
|
|
436
|
+
signal?.throwIfAborted();
|
|
437
|
+
const { modelId } = modelResolve.resolveModel(endpoints, {
|
|
438
|
+
...(explicit ? { explicit } : { modelClass: ModelClass.Embedding }),
|
|
503
439
|
});
|
|
440
|
+
return string.trimToNull(modelId);
|
|
504
441
|
}
|
|
505
442
|
|
|
506
443
|
/**
|
|
@@ -571,6 +508,7 @@ export class SearchClient {
|
|
|
571
508
|
* column (`embedding`). Returns the created index's {@link IndexInfo}.
|
|
572
509
|
*/
|
|
573
510
|
async createIndex(name: string, options: CreateIndexOptions = {}): Promise<IndexInfo> {
|
|
511
|
+
this.requireLifecycle("createIndex");
|
|
574
512
|
const endpoint = options.endpoint ?? this.config.endpoint;
|
|
575
513
|
if (!endpoint) {
|
|
576
514
|
throw new ExecutionError(
|
|
@@ -652,6 +590,7 @@ export class SearchClient {
|
|
|
652
590
|
* index is present.
|
|
653
591
|
*/
|
|
654
592
|
async ensureIndex(name: string, options: CreateIndexOptions = {}): Promise<IndexInfo> {
|
|
593
|
+
this.requireLifecycle("ensureIndex");
|
|
655
594
|
try {
|
|
656
595
|
return await this.getIndex(name, options.signal);
|
|
657
596
|
} catch {
|
|
@@ -671,23 +610,7 @@ export class SearchClient {
|
|
|
671
610
|
* rows and search-by-text works immediately.
|
|
672
611
|
*/
|
|
673
612
|
async provision(name: string, options: ProvisionOptions = {}): Promise<IndexInfo> {
|
|
674
|
-
|
|
675
|
-
// Lakebase fallback: no endpoint, no embeddings, no vectors - just a
|
|
676
|
-
// Postgres full-text table. Returns an IndexInfo-shaped result so the
|
|
677
|
-
// caller's logging + readiness handling is identical to Vector Search.
|
|
678
|
-
const rowCount = await this.lakebase.provision(name, {
|
|
679
|
-
textColumn: options.embeddingSourceColumn ?? "text",
|
|
680
|
-
...(options.seed ? { seed: options.seed } : {}),
|
|
681
|
-
...(options.signal ? { signal: options.signal } : {}),
|
|
682
|
-
});
|
|
683
|
-
return {
|
|
684
|
-
name,
|
|
685
|
-
primaryKey: options.primaryKey ?? "id",
|
|
686
|
-
columns: [],
|
|
687
|
-
ready: true,
|
|
688
|
-
rowCount,
|
|
689
|
-
};
|
|
690
|
-
}
|
|
613
|
+
this.requireLifecycle("provision");
|
|
691
614
|
const wait = options.wait ?? true;
|
|
692
615
|
const timeoutMs = options.timeoutMs ?? 20 * 60 * 1000;
|
|
693
616
|
const endpoint = options.endpoint ?? this.config.endpoint;
|
|
@@ -742,6 +665,7 @@ export class SearchClient {
|
|
|
742
665
|
|
|
743
666
|
/** Trigger a sync of a Delta Sync index from its source table. */
|
|
744
667
|
async syncIndex(reference: string, signal?: AbortSignal): Promise<void> {
|
|
668
|
+
this.requireLifecycle("syncIndex");
|
|
745
669
|
const name = this.requireIndexName(reference, "syncIndex");
|
|
746
670
|
await this.withClient("syncIndex", signal, (client, context) =>
|
|
747
671
|
client.vectorSearchIndexes.syncIndex({ index_name: name }, context),
|
|
@@ -751,6 +675,7 @@ export class SearchClient {
|
|
|
751
675
|
|
|
752
676
|
/** Delete an index. */
|
|
753
677
|
async deleteIndex(reference: string, signal?: AbortSignal): Promise<void> {
|
|
678
|
+
this.requireLifecycle("deleteIndex");
|
|
754
679
|
const name = this.requireIndexName(reference, "deleteIndex");
|
|
755
680
|
await this.withClient("deleteIndex", signal, (client, context) =>
|
|
756
681
|
client.vectorSearchIndexes.deleteIndex({ index_name: name }, context),
|
|
@@ -760,6 +685,7 @@ export class SearchClient {
|
|
|
760
685
|
|
|
761
686
|
/** List the indexes hosted on a Vector Search endpoint (name + type only). */
|
|
762
687
|
async listIndexes(endpoint?: string, signal?: AbortSignal): Promise<string[]> {
|
|
688
|
+
this.requireLifecycle("listIndexes");
|
|
763
689
|
const endpointName = endpoint ?? this.config.endpoint;
|
|
764
690
|
if (!endpointName) {
|
|
765
691
|
throw new ExecutionError("search: no endpoint configured to list indexes", {
|
|
@@ -783,6 +709,7 @@ export class SearchClient {
|
|
|
783
709
|
* does not. Optionally wait for it to come online. Idempotent.
|
|
784
710
|
*/
|
|
785
711
|
async ensureEndpoint(name?: string, options: EnsureEndpointOptions = {}): Promise<void> {
|
|
712
|
+
this.requireLifecycle("ensureEndpoint");
|
|
786
713
|
const endpoint = name ?? this.config.endpoint;
|
|
787
714
|
if (!endpoint) {
|
|
788
715
|
throw new ExecutionError("search: no endpoint name to ensure", {
|
|
@@ -832,6 +759,11 @@ export class SearchClient {
|
|
|
832
759
|
|
|
833
760
|
/** The OBO workspace client from the active context, or a service-principal client. */
|
|
834
761
|
function defaultWorkspaceClient(): WorkspaceClientLike {
|
|
762
|
+
return defaultAppKitWorkspaceClient().toLegacyWorkspaceClient();
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
/** AppKit workspace-client facade from the active request or service context. */
|
|
766
|
+
function defaultAppKitWorkspaceClient(): appkit.WorkspaceClientLike {
|
|
835
767
|
const ctx = appkit.tryGetExecutionContext();
|
|
836
768
|
if (ctx?.client) return ctx.client;
|
|
837
769
|
// Outside a request scope (a script, a test): a fresh env-auth client.
|
|
@@ -842,7 +774,7 @@ function defaultWorkspaceClient(): WorkspaceClientLike {
|
|
|
842
774
|
export function createSearchClient(
|
|
843
775
|
config?: ResolvedSearchConfig,
|
|
844
776
|
workspaceClientFactory?: () => WorkspaceClientLike,
|
|
845
|
-
|
|
777
|
+
readBackend?: SearchReadBackend,
|
|
846
778
|
): SearchClient {
|
|
847
|
-
return new SearchClient(config, workspaceClientFactory,
|
|
779
|
+
return new SearchClient(config, workspaceClientFactory, readBackend);
|
|
848
780
|
}
|