@karmaniverous/jeeves-watcher 0.9.1 → 0.9.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/jeeves-watcher/index.js +52 -19
- package/dist/index.js +52 -19
- package/package.json +1 -3
|
@@ -25,7 +25,6 @@ import { JSONPath } from 'jsonpath-plus';
|
|
|
25
25
|
import { createHash } from 'node:crypto';
|
|
26
26
|
import crypto from 'crypto';
|
|
27
27
|
import { cosmiconfig } from 'cosmiconfig';
|
|
28
|
-
import { GoogleGenerativeAIEmbeddings } from '@langchain/google-genai';
|
|
29
28
|
import pino from 'pino';
|
|
30
29
|
import { v5 } from 'uuid';
|
|
31
30
|
import * as cheerio from 'cheerio';
|
|
@@ -2785,6 +2784,16 @@ function isFacetable(prop) {
|
|
|
2785
2784
|
return false;
|
|
2786
2785
|
return prop.uiHint !== undefined || prop.enum !== undefined;
|
|
2787
2786
|
}
|
|
2787
|
+
/** uiHint types that represent enumerated value selection. */
|
|
2788
|
+
const ENUMERATED_HINTS = new Set(['dropdown', 'tags', 'select', 'multiselect']);
|
|
2789
|
+
/**
|
|
2790
|
+
* Check whether a uiHint type supports value enumeration.
|
|
2791
|
+
* Non-enumerated hints (text, number, date, range, etc.) should not
|
|
2792
|
+
* aggregate live values — the client uses free-form input instead.
|
|
2793
|
+
*/
|
|
2794
|
+
function isEnumeratedHint(uiHint) {
|
|
2795
|
+
return ENUMERATED_HINTS.has(uiHint);
|
|
2796
|
+
}
|
|
2788
2797
|
/**
|
|
2789
2798
|
* Build the schema-derived facet structure from inference rules.
|
|
2790
2799
|
*
|
|
@@ -2846,20 +2855,31 @@ function createFacetsHandler(deps) {
|
|
|
2846
2855
|
const allValues = valuesManager.getAll();
|
|
2847
2856
|
const facets = [];
|
|
2848
2857
|
for (const [field, schema] of cached.fields) {
|
|
2849
|
-
//
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
|
|
2858
|
+
// Only aggregate live values for enumerated hint types (dropdown, tags, etc.)
|
|
2859
|
+
// Non-enumerated types (text, number, date, range) use free-form input.
|
|
2860
|
+
let values;
|
|
2861
|
+
if (schema.enumValues) {
|
|
2862
|
+
values = schema.enumValues;
|
|
2863
|
+
}
|
|
2864
|
+
else if (isEnumeratedHint(schema.uiHint)) {
|
|
2865
|
+
const liveValues = new Set();
|
|
2866
|
+
for (const ruleName of schema.rules) {
|
|
2867
|
+
const fieldValues = allValues[ruleName]?.[field];
|
|
2868
|
+
if (fieldValues) {
|
|
2869
|
+
for (const v of fieldValues)
|
|
2870
|
+
liveValues.add(v);
|
|
2871
|
+
}
|
|
2856
2872
|
}
|
|
2873
|
+
values = [...liveValues].sort();
|
|
2874
|
+
}
|
|
2875
|
+
else {
|
|
2876
|
+
values = [];
|
|
2857
2877
|
}
|
|
2858
2878
|
facets.push({
|
|
2859
2879
|
field,
|
|
2860
2880
|
type: schema.type,
|
|
2861
2881
|
uiHint: schema.uiHint,
|
|
2862
|
-
values
|
|
2882
|
+
values,
|
|
2863
2883
|
rules: schema.rules,
|
|
2864
2884
|
});
|
|
2865
2885
|
}
|
|
@@ -3876,10 +3896,11 @@ function getLogger(logger) {
|
|
|
3876
3896
|
|
|
3877
3897
|
/**
|
|
3878
3898
|
* @module embedding/geminiProvider
|
|
3879
|
-
* Gemini embedding provider using Google Generative AI.
|
|
3899
|
+
* Gemini embedding provider using the Google Generative AI REST API directly.
|
|
3880
3900
|
*/
|
|
3901
|
+
const GEMINI_API_BASE = 'https://generativelanguage.googleapis.com/v1beta';
|
|
3881
3902
|
/**
|
|
3882
|
-
* Create a Gemini embedding provider using the Google Generative AI
|
|
3903
|
+
* Create a Gemini embedding provider using the Google Generative AI REST API.
|
|
3883
3904
|
*
|
|
3884
3905
|
* @param config - The embedding configuration.
|
|
3885
3906
|
* @param logger - Optional pino logger for retry warnings.
|
|
@@ -3891,20 +3912,32 @@ function createGeminiProvider(config, logger) {
|
|
|
3891
3912
|
throw new Error('Gemini embedding provider requires config.embedding.apiKey');
|
|
3892
3913
|
}
|
|
3893
3914
|
const dimensions = config.dimensions ?? 3072;
|
|
3915
|
+
const model = config.model;
|
|
3916
|
+
const apiKey = config.apiKey;
|
|
3894
3917
|
const log = getLogger(logger);
|
|
3895
|
-
const
|
|
3896
|
-
apiKey: config.apiKey,
|
|
3897
|
-
model: config.model,
|
|
3898
|
-
});
|
|
3918
|
+
const url = `${GEMINI_API_BASE}/models/${model}:batchEmbedContents?key=${apiKey}`;
|
|
3899
3919
|
return {
|
|
3900
3920
|
dimensions,
|
|
3901
3921
|
async embed(texts) {
|
|
3902
3922
|
const vectors = await retry(async (attempt) => {
|
|
3903
3923
|
if (attempt > 1) {
|
|
3904
|
-
log.warn({ attempt, provider: 'gemini', model
|
|
3924
|
+
log.warn({ attempt, provider: 'gemini', model }, 'Retrying embedding request');
|
|
3925
|
+
}
|
|
3926
|
+
const requests = texts.map((text) => ({
|
|
3927
|
+
model: `models/${model}`,
|
|
3928
|
+
content: { parts: [{ text }] },
|
|
3929
|
+
}));
|
|
3930
|
+
const response = await fetch(url, {
|
|
3931
|
+
method: 'POST',
|
|
3932
|
+
headers: { 'Content-Type': 'application/json' },
|
|
3933
|
+
body: JSON.stringify({ requests }),
|
|
3934
|
+
});
|
|
3935
|
+
if (!response.ok) {
|
|
3936
|
+
const body = await response.text();
|
|
3937
|
+
throw new Error(`Gemini API error ${String(response.status)}: ${body}`);
|
|
3905
3938
|
}
|
|
3906
|
-
|
|
3907
|
-
return
|
|
3939
|
+
const data = (await response.json());
|
|
3940
|
+
return data.embeddings.map((e) => e.values);
|
|
3908
3941
|
}, {
|
|
3909
3942
|
attempts: 5,
|
|
3910
3943
|
baseDelayMs: 500,
|
|
@@ -3915,7 +3948,7 @@ function createGeminiProvider(config, logger) {
|
|
|
3915
3948
|
attempt,
|
|
3916
3949
|
delayMs,
|
|
3917
3950
|
provider: 'gemini',
|
|
3918
|
-
model
|
|
3951
|
+
model,
|
|
3919
3952
|
err: normalizeError(error),
|
|
3920
3953
|
}, 'Embedding call failed; will retry');
|
|
3921
3954
|
},
|
package/dist/index.js
CHANGED
|
@@ -22,7 +22,6 @@ import { createHash } from 'node:crypto';
|
|
|
22
22
|
import crypto from 'crypto';
|
|
23
23
|
import chokidar from 'chokidar';
|
|
24
24
|
import { cosmiconfig } from 'cosmiconfig';
|
|
25
|
-
import { GoogleGenerativeAIEmbeddings } from '@langchain/google-genai';
|
|
26
25
|
import pino from 'pino';
|
|
27
26
|
import { v5 } from 'uuid';
|
|
28
27
|
import * as cheerio from 'cheerio';
|
|
@@ -2471,6 +2470,16 @@ function isFacetable(prop) {
|
|
|
2471
2470
|
return false;
|
|
2472
2471
|
return prop.uiHint !== undefined || prop.enum !== undefined;
|
|
2473
2472
|
}
|
|
2473
|
+
/** uiHint types that represent enumerated value selection. */
|
|
2474
|
+
const ENUMERATED_HINTS = new Set(['dropdown', 'tags', 'select', 'multiselect']);
|
|
2475
|
+
/**
|
|
2476
|
+
* Check whether a uiHint type supports value enumeration.
|
|
2477
|
+
* Non-enumerated hints (text, number, date, range, etc.) should not
|
|
2478
|
+
* aggregate live values — the client uses free-form input instead.
|
|
2479
|
+
*/
|
|
2480
|
+
function isEnumeratedHint(uiHint) {
|
|
2481
|
+
return ENUMERATED_HINTS.has(uiHint);
|
|
2482
|
+
}
|
|
2474
2483
|
/**
|
|
2475
2484
|
* Build the schema-derived facet structure from inference rules.
|
|
2476
2485
|
*
|
|
@@ -2532,20 +2541,31 @@ function createFacetsHandler(deps) {
|
|
|
2532
2541
|
const allValues = valuesManager.getAll();
|
|
2533
2542
|
const facets = [];
|
|
2534
2543
|
for (const [field, schema] of cached.fields) {
|
|
2535
|
-
//
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2544
|
+
// Only aggregate live values for enumerated hint types (dropdown, tags, etc.)
|
|
2545
|
+
// Non-enumerated types (text, number, date, range) use free-form input.
|
|
2546
|
+
let values;
|
|
2547
|
+
if (schema.enumValues) {
|
|
2548
|
+
values = schema.enumValues;
|
|
2549
|
+
}
|
|
2550
|
+
else if (isEnumeratedHint(schema.uiHint)) {
|
|
2551
|
+
const liveValues = new Set();
|
|
2552
|
+
for (const ruleName of schema.rules) {
|
|
2553
|
+
const fieldValues = allValues[ruleName]?.[field];
|
|
2554
|
+
if (fieldValues) {
|
|
2555
|
+
for (const v of fieldValues)
|
|
2556
|
+
liveValues.add(v);
|
|
2557
|
+
}
|
|
2542
2558
|
}
|
|
2559
|
+
values = [...liveValues].sort();
|
|
2560
|
+
}
|
|
2561
|
+
else {
|
|
2562
|
+
values = [];
|
|
2543
2563
|
}
|
|
2544
2564
|
facets.push({
|
|
2545
2565
|
field,
|
|
2546
2566
|
type: schema.type,
|
|
2547
2567
|
uiHint: schema.uiHint,
|
|
2548
|
-
values
|
|
2568
|
+
values,
|
|
2549
2569
|
rules: schema.rules,
|
|
2550
2570
|
});
|
|
2551
2571
|
}
|
|
@@ -3852,10 +3872,11 @@ function getLogger(logger) {
|
|
|
3852
3872
|
|
|
3853
3873
|
/**
|
|
3854
3874
|
* @module embedding/geminiProvider
|
|
3855
|
-
* Gemini embedding provider using Google Generative AI.
|
|
3875
|
+
* Gemini embedding provider using the Google Generative AI REST API directly.
|
|
3856
3876
|
*/
|
|
3877
|
+
const GEMINI_API_BASE = 'https://generativelanguage.googleapis.com/v1beta';
|
|
3857
3878
|
/**
|
|
3858
|
-
* Create a Gemini embedding provider using the Google Generative AI
|
|
3879
|
+
* Create a Gemini embedding provider using the Google Generative AI REST API.
|
|
3859
3880
|
*
|
|
3860
3881
|
* @param config - The embedding configuration.
|
|
3861
3882
|
* @param logger - Optional pino logger for retry warnings.
|
|
@@ -3867,20 +3888,32 @@ function createGeminiProvider(config, logger) {
|
|
|
3867
3888
|
throw new Error('Gemini embedding provider requires config.embedding.apiKey');
|
|
3868
3889
|
}
|
|
3869
3890
|
const dimensions = config.dimensions ?? 3072;
|
|
3891
|
+
const model = config.model;
|
|
3892
|
+
const apiKey = config.apiKey;
|
|
3870
3893
|
const log = getLogger(logger);
|
|
3871
|
-
const
|
|
3872
|
-
apiKey: config.apiKey,
|
|
3873
|
-
model: config.model,
|
|
3874
|
-
});
|
|
3894
|
+
const url = `${GEMINI_API_BASE}/models/${model}:batchEmbedContents?key=${apiKey}`;
|
|
3875
3895
|
return {
|
|
3876
3896
|
dimensions,
|
|
3877
3897
|
async embed(texts) {
|
|
3878
3898
|
const vectors = await retry(async (attempt) => {
|
|
3879
3899
|
if (attempt > 1) {
|
|
3880
|
-
log.warn({ attempt, provider: 'gemini', model
|
|
3900
|
+
log.warn({ attempt, provider: 'gemini', model }, 'Retrying embedding request');
|
|
3901
|
+
}
|
|
3902
|
+
const requests = texts.map((text) => ({
|
|
3903
|
+
model: `models/${model}`,
|
|
3904
|
+
content: { parts: [{ text }] },
|
|
3905
|
+
}));
|
|
3906
|
+
const response = await fetch(url, {
|
|
3907
|
+
method: 'POST',
|
|
3908
|
+
headers: { 'Content-Type': 'application/json' },
|
|
3909
|
+
body: JSON.stringify({ requests }),
|
|
3910
|
+
});
|
|
3911
|
+
if (!response.ok) {
|
|
3912
|
+
const body = await response.text();
|
|
3913
|
+
throw new Error(`Gemini API error ${String(response.status)}: ${body}`);
|
|
3881
3914
|
}
|
|
3882
|
-
|
|
3883
|
-
return
|
|
3915
|
+
const data = (await response.json());
|
|
3916
|
+
return data.embeddings.map((e) => e.values);
|
|
3884
3917
|
}, {
|
|
3885
3918
|
attempts: 5,
|
|
3886
3919
|
baseDelayMs: 500,
|
|
@@ -3891,7 +3924,7 @@ function createGeminiProvider(config, logger) {
|
|
|
3891
3924
|
attempt,
|
|
3892
3925
|
delayMs,
|
|
3893
3926
|
provider: 'gemini',
|
|
3894
|
-
model
|
|
3927
|
+
model,
|
|
3895
3928
|
err: normalizeError(error),
|
|
3896
3929
|
}, 'Embedding call failed; will retry');
|
|
3897
3930
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@karmaniverous/jeeves-watcher",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.3",
|
|
4
4
|
"author": "Jason Williscroft",
|
|
5
5
|
"description": "Filesystem watcher that keeps a Qdrant vector store in sync with document changes",
|
|
6
6
|
"license": "BSD-3-Clause",
|
|
@@ -52,8 +52,6 @@
|
|
|
52
52
|
"dependencies": {
|
|
53
53
|
"@commander-js/extra-typings": "^14.0.0",
|
|
54
54
|
"@karmaniverous/jsonmap": "^2.1.1",
|
|
55
|
-
"@langchain/google-genai": "*",
|
|
56
|
-
"@langchain/qdrant": "*",
|
|
57
55
|
"@langchain/textsplitters": "*",
|
|
58
56
|
"@qdrant/js-client-rest": "*",
|
|
59
57
|
"ajv": "^8.18.0",
|