@far-world-labs/verblets 0.1.1 → 0.1.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/.cursor/launch.json +30 -0
- package/.cursor/settings.json +20 -0
- package/.github/workflows/branch-protection.yml +22 -0
- package/.github/workflows/ci.yml +120 -0
- package/.prettierrc +6 -0
- package/.release-it.json +4 -1
- package/.vscode/launch.json +31 -0
- package/AGENTS.md +220 -0
- package/DEVELOPING.md +105 -0
- package/README.md +254 -0
- package/eslint.config.js +80 -0
- package/package.json +29 -17
- package/scripts/generate-test/index.js +29 -3
- package/scripts/runner/index.js +26 -0
- package/scripts/simple-editor/index.js +29 -18
- package/scripts/summarize-files/index.js +28 -4
- package/src/chains/README.md +30 -0
- package/src/chains/anonymize/README.md +21 -0
- package/src/chains/anonymize/index.examples.js +75 -0
- package/src/chains/anonymize/index.js +121 -0
- package/src/chains/anonymize/index.spec.js +78 -0
- package/src/chains/bulk-central-tendency/index.examples.js +138 -0
- package/src/chains/bulk-central-tendency/index.js +91 -0
- package/src/chains/bulk-filter/README.md +21 -0
- package/src/chains/bulk-filter/index.examples.js +22 -0
- package/src/chains/bulk-filter/index.js +58 -0
- package/src/chains/bulk-filter/index.spec.js +38 -0
- package/src/chains/bulk-find/README.md +16 -0
- package/src/chains/bulk-find/index.examples.js +20 -0
- package/src/chains/bulk-find/index.js +30 -0
- package/src/chains/bulk-find/index.spec.js +26 -0
- package/src/chains/bulk-group/README.md +23 -0
- package/src/chains/bulk-group/index.examples.js +18 -0
- package/src/chains/bulk-group/index.js +34 -0
- package/src/chains/bulk-group/index.spec.js +41 -0
- package/src/chains/bulk-map/README.md +43 -0
- package/src/chains/bulk-map/index.examples.js +17 -0
- package/src/chains/bulk-map/index.js +86 -0
- package/src/chains/bulk-map/index.spec.js +44 -0
- package/src/chains/bulk-reduce/README.md +12 -0
- package/src/chains/bulk-reduce/index.examples.js +15 -0
- package/src/chains/bulk-reduce/index.js +13 -0
- package/src/chains/bulk-reduce/index.spec.js +25 -0
- package/src/chains/bulk-score/README.md +16 -0
- package/src/chains/bulk-score/bulk-score-result.json +18 -0
- package/src/chains/bulk-score/index.examples.js +22 -0
- package/src/chains/bulk-score/index.js +133 -0
- package/src/chains/bulk-score/index.spec.js +30 -0
- package/src/chains/category-samples/README.md +61 -0
- package/src/chains/category-samples/index.examples.js +103 -0
- package/src/chains/category-samples/index.js +134 -0
- package/src/chains/collect-terms/README.md +12 -0
- package/src/chains/collect-terms/index.examples.js +16 -0
- package/src/chains/collect-terms/index.js +44 -0
- package/src/chains/collect-terms/index.spec.js +25 -0
- package/src/chains/date/README.md +12 -0
- package/src/chains/date/index.examples.js +47 -0
- package/src/chains/date/index.js +74 -0
- package/src/chains/date/index.spec.js +62 -0
- package/src/chains/disambiguate/README.md +22 -0
- package/src/chains/disambiguate/disambiguate-meanings-result.json +16 -0
- package/src/chains/disambiguate/index.examples.js +18 -0
- package/src/chains/disambiguate/index.js +92 -0
- package/src/chains/disambiguate/index.spec.js +25 -0
- package/src/chains/dismantle/README.md +67 -0
- package/src/chains/dismantle/dismantle.examples.js +27 -0
- package/src/chains/dismantle/index.js +6 -17
- package/src/chains/dismantle/index.spec.js +1 -2
- package/src/chains/expect/README.md +171 -0
- package/src/chains/expect/index.examples.js +146 -0
- package/src/chains/expect/index.js +173 -0
- package/src/chains/expect/index.spec.js +324 -0
- package/src/chains/filter-ambiguous/README.md +11 -0
- package/src/chains/filter-ambiguous/index.examples.js +20 -0
- package/src/chains/filter-ambiguous/index.js +49 -0
- package/src/chains/filter-ambiguous/index.spec.js +31 -0
- package/src/chains/glossary/README.md +19 -0
- package/src/chains/glossary/index.examples.js +386 -0
- package/src/chains/glossary/index.js +75 -0
- package/src/chains/glossary/index.spec.js +19 -0
- package/src/chains/intersections/README.md +152 -0
- package/src/chains/intersections/index.examples.js +279 -0
- package/src/chains/intersections/index.js +366 -0
- package/src/chains/intersections/intersection-result.json +38 -0
- package/src/chains/list/index.examples.js +12 -16
- package/src/chains/list/index.js +106 -53
- package/src/chains/list/index.spec.js +8 -9
- package/src/chains/list/list-result.json +16 -0
- package/src/chains/llm-logger/README.md +208 -0
- package/src/chains/llm-logger/index.js +205 -0
- package/src/chains/llm-logger/index.spec.js +330 -0
- package/src/chains/questions/index.examples.js +2 -1
- package/src/chains/questions/index.js +14 -15
- package/src/chains/scan-js/index.js +6 -9
- package/src/chains/set-interval/README.md +81 -0
- package/src/chains/set-interval/index.examples.js +36 -0
- package/src/chains/set-interval/index.js +131 -0
- package/src/chains/set-interval/index.spec.js +70 -0
- package/src/chains/socratic/README.md +17 -0
- package/src/chains/socratic/index.js +64 -0
- package/src/chains/socratic/index.spec.js +24 -0
- package/src/chains/sort/index.examples.js +3 -7
- package/src/chains/sort/index.js +65 -15
- package/src/chains/sort/index.spec.js +5 -8
- package/src/chains/sort/sort-result.json +16 -0
- package/src/chains/summary-map/README.md +9 -1
- package/src/chains/summary-map/index.examples.js +9 -2
- package/src/chains/summary-map/index.js +43 -25
- package/src/chains/summary-map/index.spec.js +78 -3
- package/src/chains/test/index.js +9 -13
- package/src/chains/test-advice/index.js +4 -5
- package/src/chains/themes/README.md +20 -0
- package/src/chains/themes/index.examples.js +17 -0
- package/src/chains/themes/index.js +28 -0
- package/src/chains/themes/index.spec.js +19 -0
- package/src/chains/veiled-variants/index.examples.js +18 -0
- package/src/chains/veiled-variants/index.js +107 -0
- package/src/chains/veiled-variants/index.spec.js +40 -0
- package/src/constants/common.js +0 -2
- package/src/constants/models.js +172 -0
- package/src/index.js +178 -18
- package/src/json-schemas/README.md +13 -0
- package/src/json-schemas/index.js +8 -14
- package/src/json-schemas/schema-dot-org-photograph.json +11 -5
- package/src/json-schemas/schema-dot-org-place.json +78 -5
- package/src/lib/README.md +26 -0
- package/src/lib/bulk-filter/README.md +22 -0
- package/src/lib/bulk-filter/index.examples.js +27 -0
- package/src/lib/bulk-filter/index.js +63 -0
- package/src/lib/bulk-filter/index.spec.js +38 -0
- package/src/lib/bulk-find/README.md +18 -0
- package/src/lib/bulk-find/index.examples.js +19 -0
- package/src/lib/bulk-find/index.js +30 -0
- package/src/lib/bulk-find/index.spec.js +41 -0
- package/src/lib/chatgpt/index.js +63 -43
- package/src/lib/combinations/index.js +30 -0
- package/src/lib/combinations/index.spec.js +23 -0
- package/src/lib/functional/index.js +28 -0
- package/src/lib/logger-service/index.js +32 -0
- package/src/lib/parse-js-parts/index.js +9 -21
- package/src/lib/parse-llm-list/README.md +39 -0
- package/src/lib/parse-llm-list/index.js +54 -0
- package/src/lib/parse-llm-list/index.spec.js +59 -0
- package/src/lib/path-aliases/index.js +1 -3
- package/src/lib/path-aliases/index.spec.js +2 -8
- package/src/lib/pave/index.js +4 -4
- package/src/lib/pave/index.spec.js +6 -3
- package/src/lib/prompt-cache/index.js +14 -10
- package/src/lib/retry/index.js +11 -8
- package/src/lib/ring-buffer/README.md +460 -0
- package/src/lib/ring-buffer/index.js +1074 -0
- package/src/lib/search-best-first/city-walk.spec.js +37 -0
- package/src/lib/search-best-first/index.js +42 -11
- package/src/lib/search-best-first/index.spec.js +35 -0
- package/src/lib/search-js-files/index.js +44 -47
- package/src/lib/search-js-files/scan-file.js +10 -21
- package/src/lib/shorten-text/index.js +2 -7
- package/src/lib/shorten-text/index.spec.js +3 -3
- package/src/lib/strip-response/index.js +2 -7
- package/src/lib/template-replace/index.js +23 -0
- package/src/lib/template-replace/index.spec.js +60 -0
- package/src/lib/to-date/index.js +11 -0
- package/src/lib/to-number/index.js +1 -1
- package/src/lib/transcribe/index.js +26 -9
- package/src/prompts/README.md +3 -1
- package/src/prompts/as-object-with-schema.js +3 -8
- package/src/prompts/as-schema-org-text.js +10 -2
- package/src/prompts/code-features.js +1 -5
- package/src/prompts/constants.js +27 -27
- package/src/prompts/generate-collection.js +1 -1
- package/src/prompts/intent.js +16 -22
- package/src/prompts/select-from-threshold.js +1 -2
- package/src/prompts/sort.js +4 -8
- package/src/prompts/style.js +4 -7
- package/src/prompts/wrap-list.js +1 -4
- package/src/services/llm-model/global-overrides.spec.js +432 -0
- package/src/services/llm-model/index.js +234 -40
- package/src/services/llm-model/model.js +2 -2
- package/src/services/llm-model/negotiate.spec.js +447 -0
- package/src/services/redis/index.js +70 -7
- package/src/test/setup.js +20 -0
- package/src/verblets/README.md +26 -0
- package/src/verblets/auto/index.examples.js +12 -9
- package/src/verblets/auto/index.js +10 -10
- package/src/verblets/auto/index.spec.js +4 -6
- package/src/verblets/bool/README.md +36 -0
- package/src/verblets/bool/index.examples.js +53 -1
- package/src/verblets/bool/index.js +6 -9
- package/src/verblets/bool/index.spec.js +1 -3
- package/src/verblets/central-tendency/README.md +166 -0
- package/src/verblets/central-tendency/central-tendency-result.json +24 -0
- package/src/verblets/central-tendency/index.examples.js +196 -0
- package/src/verblets/central-tendency/index.js +171 -0
- package/src/verblets/central-tendency/index.spec.js +148 -0
- package/src/verblets/enum/index.examples.js +1 -4
- package/src/verblets/enum/index.js +7 -4
- package/src/verblets/expect/README.md +64 -0
- package/src/verblets/expect/index.examples.js +109 -0
- package/src/verblets/expect/index.js +75 -0
- package/src/verblets/expect/index.spec.js +127 -0
- package/src/verblets/intent/index.examples.js +95 -7
- package/src/verblets/intent/index.js +56 -68
- package/src/verblets/intersection/README.md +16 -0
- package/src/verblets/intersection/index.examples.js +89 -0
- package/src/verblets/intersection/index.js +84 -0
- package/src/verblets/intersection/index.spec.js +60 -0
- package/src/verblets/intersection/intersection-result.json +16 -0
- package/src/verblets/list-expand/README.md +10 -0
- package/src/verblets/list-expand/index.examples.js +14 -0
- package/src/verblets/list-expand/index.js +104 -0
- package/src/verblets/list-expand/index.spec.js +18 -0
- package/src/verblets/list-expand/list-expand-result.json +16 -0
- package/src/verblets/list-filter/README.md +22 -0
- package/src/verblets/list-filter/index.examples.js +26 -0
- package/src/verblets/list-filter/index.js +18 -0
- package/src/verblets/list-filter/index.spec.js +19 -0
- package/src/verblets/list-find/README.md +11 -0
- package/src/verblets/list-find/index.examples.js +15 -0
- package/src/verblets/list-find/index.js +17 -0
- package/src/verblets/list-find/index.spec.js +19 -0
- package/src/verblets/list-group/README.md +16 -0
- package/src/verblets/list-group/index.examples.js +16 -0
- package/src/verblets/list-group/index.js +112 -0
- package/src/verblets/list-group/index.spec.js +35 -0
- package/src/verblets/list-group/list-group-result.json +16 -0
- package/src/verblets/list-map/README.md +11 -0
- package/src/verblets/list-map/index.examples.js +15 -0
- package/src/verblets/list-map/index.js +26 -0
- package/src/verblets/list-map/index.spec.js +17 -0
- package/src/verblets/list-reduce/README.md +10 -0
- package/src/verblets/list-reduce/index.examples.js +14 -0
- package/src/verblets/list-reduce/index.js +21 -0
- package/src/verblets/list-reduce/index.spec.js +27 -0
- package/src/verblets/list-reduce/index.spec.jsx +27 -0
- package/src/verblets/name/README.md +15 -0
- package/src/verblets/name/index.examples.js +28 -0
- package/src/verblets/name/index.js +19 -0
- package/src/verblets/name/index.spec.js +33 -0
- package/src/verblets/name-similar-to/README.md +26 -0
- package/src/verblets/name-similar-to/index.examples.js +18 -0
- package/src/verblets/name-similar-to/index.js +20 -0
- package/src/verblets/name-similar-to/index.spec.js +13 -0
- package/src/verblets/number/index.examples.js +173 -7
- package/src/verblets/number/index.js +5 -2
- package/src/verblets/number/index.spec.js +1 -3
- package/src/verblets/number-with-units/index.examples.js +5 -1
- package/src/verblets/number-with-units/index.js +74 -9
- package/src/verblets/number-with-units/number-with-units-result.json +23 -0
- package/src/verblets/schema-org/index.examples.js +2 -7
- package/src/verblets/schema-org/index.js +32 -3
- package/src/verblets/sentiment/README.md +10 -0
- package/src/verblets/sentiment/index.examples.js +20 -0
- package/src/verblets/sentiment/index.js +9 -0
- package/src/verblets/sentiment/index.spec.js +20 -0
- package/src/verblets/to-object/index.js +10 -15
- package/src/verblets/to-object/index.spec.js +1 -4
- package/.eslintrc.json +0 -42
- package/docs/README.md +0 -41
- package/docs/babel.config.js +0 -3
- package/docs/blog/2019-05-28-first-blog-post.md +0 -12
- package/docs/blog/2019-05-29-long-blog-post.md +0 -44
- package/docs/blog/2021-08-01-mdx-blog-post.mdx +0 -20
- package/docs/blog/2021-08-26-welcome/docusaurus-plushie-banner.jpeg +0 -0
- package/docs/blog/2021-08-26-welcome/index.md +0 -25
- package/docs/blog/authors.yml +0 -17
- package/docs/docs/api/bool.md +0 -74
- package/docs/docs/api/search.md +0 -51
- package/docs/docs/intro.md +0 -47
- package/docs/docs/tutorial-basics/_category_.json +0 -8
- package/docs/docs/tutorial-basics/congratulations.md +0 -23
- package/docs/docs/tutorial-basics/create-a-blog-post.md +0 -34
- package/docs/docs/tutorial-basics/create-a-document.md +0 -57
- package/docs/docs/tutorial-basics/create-a-page.md +0 -43
- package/docs/docs/tutorial-basics/deploy-your-site.md +0 -31
- package/docs/docs/tutorial-basics/markdown-features.mdx +0 -152
- package/docs/docs/tutorial-extras/_category_.json +0 -7
- package/docs/docs/tutorial-extras/img/docsVersionDropdown.png +0 -0
- package/docs/docs/tutorial-extras/img/localeDropdown.png +0 -0
- package/docs/docs/tutorial-extras/manage-docs-versions.md +0 -55
- package/docs/docs/tutorial-extras/translate-your-site.md +0 -88
- package/docs/docusaurus.config.js +0 -120
- package/docs/package.json +0 -44
- package/docs/sidebars.js +0 -31
- package/docs/src/components/HomepageFeatures/index.js +0 -61
- package/docs/src/components/HomepageFeatures/styles.module.css +0 -11
- package/docs/src/css/custom.css +0 -30
- package/docs/src/pages/index.js +0 -43
- package/docs/src/pages/index.module.css +0 -23
- package/docs/src/pages/markdown-page.md +0 -7
- package/docs/static/.nojekyll +0 -0
- package/docs/static/img/docusaurus-social-card.jpg +0 -0
- package/docs/static/img/docusaurus.png +0 -0
- package/docs/static/img/favicon.ico +0 -0
- package/docs/static/img/logo.svg +0 -1
- package/docs/static/img/undraw_docusaurus_mountain.svg +0 -171
- package/docs/static/img/undraw_docusaurus_react.svg +0 -170
- package/docs/static/img/undraw_docusaurus_tree.svg +0 -40
- package/src/constants/openai.js +0 -65
- /package/{.vite.config.examples.js → .vitest.config.examples.js} +0 -0
- /package/{.vite.config.js → .vitest.config.js} +0 -0
|
@@ -1,15 +1,10 @@
|
|
|
1
|
-
/* eslint-disable no-await-in-loop */
|
|
2
|
-
|
|
3
1
|
import chatGPT from '../../lib/chatgpt/index.js';
|
|
4
2
|
import pave from '../../lib/pave/index.js';
|
|
5
3
|
import shortenText from '../../lib/shorten-text/index.js';
|
|
6
|
-
import {
|
|
7
|
-
summarize as basicSummarize,
|
|
8
|
-
tokenBudget,
|
|
9
|
-
} from '../../prompts/index.js';
|
|
4
|
+
import { summarize as basicSummarize, tokenBudget } from '../../prompts/index.js';
|
|
10
5
|
import modelService from '../../services/llm-model/index.js';
|
|
11
6
|
|
|
12
|
-
const summarize = ({ budget, type, value, fixes = [] }) => {
|
|
7
|
+
const summarize = ({ budget, type, value, fixes = [], modelOptions, privacy }) => {
|
|
13
8
|
if (budget) {
|
|
14
9
|
fixes.push(tokenBudget(budget));
|
|
15
10
|
}
|
|
@@ -22,9 +17,19 @@ const summarize = ({ budget, type, value, fixes = [] }) => {
|
|
|
22
17
|
fixes.push('Remove the function header if it exists.');
|
|
23
18
|
}
|
|
24
19
|
|
|
20
|
+
if (privacy?.whitelist) {
|
|
21
|
+
fixes.push(`Only share information matching: ${privacy.whitelist}.`);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (privacy?.blacklist) {
|
|
25
|
+
fixes.push(`Do not share information matching: ${privacy.blacklist}.`);
|
|
26
|
+
}
|
|
27
|
+
|
|
25
28
|
const fixesAsBullets = fixes.map((fix) => ` - ${fix}`);
|
|
26
29
|
|
|
27
|
-
return chatGPT(basicSummarize(value, `${fixesAsBullets.join('\n')}`)
|
|
30
|
+
return chatGPT(basicSummarize(value, `${fixesAsBullets.join('\n')}`), {
|
|
31
|
+
modelOptions,
|
|
32
|
+
});
|
|
28
33
|
};
|
|
29
34
|
|
|
30
35
|
/**
|
|
@@ -34,7 +39,8 @@ const summarize = ({ budget, type, value, fixes = [] }) => {
|
|
|
34
39
|
export default class SummaryMap extends Map {
|
|
35
40
|
constructor({
|
|
36
41
|
maxTokensPerValue,
|
|
37
|
-
model = modelService.
|
|
42
|
+
model = modelService.getBestPublicModel(),
|
|
43
|
+
modelOptions = { modelName: model.name },
|
|
38
44
|
promptText,
|
|
39
45
|
targetTokens,
|
|
40
46
|
// used with promptText, when targetTokens isn't supplied
|
|
@@ -45,6 +51,7 @@ export default class SummaryMap extends Map {
|
|
|
45
51
|
this.data = new Map();
|
|
46
52
|
this.isCacheValid = false;
|
|
47
53
|
this.maxTokensPerValue = maxTokensPerValue ?? model.maxTokens;
|
|
54
|
+
this.modelOptions = { modelName: model.name, ...modelOptions };
|
|
48
55
|
|
|
49
56
|
if (targetTokens) {
|
|
50
57
|
this.targetTokens = targetTokens;
|
|
@@ -52,13 +59,9 @@ export default class SummaryMap extends Map {
|
|
|
52
59
|
this.promptTokens = model.toTokens(promptText).length;
|
|
53
60
|
const maxModelTokens = model.maxTokens;
|
|
54
61
|
const remainingTokens = maxModelTokens - this.promptTokens;
|
|
55
|
-
this.targetTokens = Math.floor(
|
|
56
|
-
remainingTokens - remainingTokens * targetTokensTotalRatio
|
|
57
|
-
);
|
|
62
|
+
this.targetTokens = Math.floor(remainingTokens - remainingTokens * targetTokensTotalRatio);
|
|
58
63
|
} else {
|
|
59
|
-
throw new Error(
|
|
60
|
-
'Either "promptText" and "model" or "targetTokens" must be provided.'
|
|
61
|
-
);
|
|
64
|
+
throw new Error('Either "promptText" and "model" or "targetTokens" must be provided.');
|
|
62
65
|
}
|
|
63
66
|
}
|
|
64
67
|
|
|
@@ -68,16 +71,12 @@ export default class SummaryMap extends Map {
|
|
|
68
71
|
.reduce((sum, valueObject) => {
|
|
69
72
|
return sum + (valueObject.weight ?? 1) * valueObject.value.length;
|
|
70
73
|
}, 0);
|
|
71
|
-
const sortedEntries = [...this.data.entries()].sort(
|
|
72
|
-
(a, b) => a[1].weight - b[1].weight
|
|
73
|
-
);
|
|
74
|
+
const sortedEntries = [...this.data.entries()].sort((a, b) => a[1].weight - b[1].weight);
|
|
74
75
|
|
|
75
76
|
const budgets = [];
|
|
76
77
|
for (const [entryKey, valueObject] of sortedEntries) {
|
|
77
78
|
const sizeWeight = valueObject.value.length * (valueObject.weight ?? 1);
|
|
78
|
-
const budget = Math.floor(
|
|
79
|
-
(sizeWeight / totalSizeWeight) * this.targetTokens
|
|
80
|
-
);
|
|
79
|
+
const budget = Math.floor((sizeWeight / totalSizeWeight) * this.targetTokens);
|
|
81
80
|
|
|
82
81
|
if (valueObject.weight) {
|
|
83
82
|
budgets.push({ key: entryKey, budget });
|
|
@@ -95,16 +94,38 @@ export default class SummaryMap extends Map {
|
|
|
95
94
|
for (const { key, budget } of budgets) {
|
|
96
95
|
const valueObject = this.data.get(key);
|
|
97
96
|
|
|
97
|
+
const entryModelOptions = {
|
|
98
|
+
...this.modelOptions,
|
|
99
|
+
...valueObject.modelOptions,
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
if (valueObject.privacy?.whitelist || valueObject.privacy?.blacklist) {
|
|
103
|
+
entryModelOptions.modelName = 'privacy';
|
|
104
|
+
}
|
|
105
|
+
|
|
98
106
|
const value = shortenText(valueObject.value, {
|
|
99
107
|
targetTokenCount: this.maxTokensPerValue,
|
|
108
|
+
model: modelService.getModel(entryModelOptions.modelName),
|
|
100
109
|
});
|
|
101
110
|
|
|
102
111
|
// omit weight to skip summarization
|
|
103
112
|
let summarizedValue = value;
|
|
104
113
|
if (budget) {
|
|
114
|
+
const summarizeModelOptions = {
|
|
115
|
+
...this.modelOptions,
|
|
116
|
+
...valueObject.modelOptions,
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
if (valueObject.privacy?.whitelist || valueObject.privacy?.blacklist) {
|
|
120
|
+
summarizeModelOptions.modelName = 'privacy';
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// eslint-disable-next-line no-await-in-loop
|
|
105
124
|
summarizedValue = await summarize({
|
|
106
125
|
budget,
|
|
107
126
|
fixes: valueObject.fixes,
|
|
127
|
+
modelOptions: summarizeModelOptions,
|
|
128
|
+
privacy: valueObject.privacy,
|
|
108
129
|
type: valueObject.type,
|
|
109
130
|
value,
|
|
110
131
|
});
|
|
@@ -189,10 +210,7 @@ export default class SummaryMap extends Map {
|
|
|
189
210
|
}
|
|
190
211
|
|
|
191
212
|
pavedSummaryResultStale() {
|
|
192
|
-
return Array.from(this.entriesStale()).reduce(
|
|
193
|
-
(acc, [k, v]) => pave(acc, k, v),
|
|
194
|
-
{}
|
|
195
|
-
);
|
|
213
|
+
return Array.from(this.entriesStale()).reduce((acc, [k, v]) => pave(acc, k, v), {});
|
|
196
214
|
}
|
|
197
215
|
|
|
198
216
|
pavedSummaryResult() {
|
|
@@ -1,7 +1,51 @@
|
|
|
1
1
|
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
-
|
|
3
|
-
import SummaryMap from './index.js';
|
|
4
2
|
import pave from '../../lib/pave/index.js';
|
|
3
|
+
import SummaryMap from './index.js';
|
|
4
|
+
import chatGPT from '../../lib/chatgpt/index.js';
|
|
5
|
+
|
|
6
|
+
vi.mock('../../services/llm-model/index.js', () => ({
|
|
7
|
+
default: {
|
|
8
|
+
negotiateModel: vi.fn().mockReturnValue('fastGood'),
|
|
9
|
+
getBestPublicModel: vi.fn().mockReturnValue({
|
|
10
|
+
name: 'fastGood',
|
|
11
|
+
tokenizer: (text) => text.split(' '),
|
|
12
|
+
maxContextWindow: 128000,
|
|
13
|
+
maxOutputTokens: 16384,
|
|
14
|
+
toTokens(text) {
|
|
15
|
+
return this.tokenizer(text);
|
|
16
|
+
},
|
|
17
|
+
budgetTokens(text, { completionMax = Infinity } = {}) {
|
|
18
|
+
const prompt = this.toTokens(text).length;
|
|
19
|
+
const total = this.maxContextWindow;
|
|
20
|
+
const completion = Math.min(Math.min(total - prompt, this.maxOutputTokens), completionMax);
|
|
21
|
+
return {
|
|
22
|
+
completion,
|
|
23
|
+
prompt,
|
|
24
|
+
total,
|
|
25
|
+
};
|
|
26
|
+
},
|
|
27
|
+
}),
|
|
28
|
+
getModel: vi.fn().mockReturnValue({
|
|
29
|
+
name: 'fastGood',
|
|
30
|
+
tokenizer: (text) => text.split(' '),
|
|
31
|
+
maxContextWindow: 128000,
|
|
32
|
+
maxOutputTokens: 16384,
|
|
33
|
+
toTokens(text) {
|
|
34
|
+
return this.tokenizer(text);
|
|
35
|
+
},
|
|
36
|
+
budgetTokens(text, { completionMax = Infinity } = {}) {
|
|
37
|
+
const prompt = this.toTokens(text).length;
|
|
38
|
+
const total = this.maxContextWindow;
|
|
39
|
+
const completion = Math.min(Math.min(total - prompt, this.maxOutputTokens), completionMax);
|
|
40
|
+
return {
|
|
41
|
+
completion,
|
|
42
|
+
prompt,
|
|
43
|
+
total,
|
|
44
|
+
};
|
|
45
|
+
},
|
|
46
|
+
}),
|
|
47
|
+
},
|
|
48
|
+
}));
|
|
5
49
|
|
|
6
50
|
vi.mock('../../lib/chatgpt/index.js', () => ({
|
|
7
51
|
default: vi.fn().mockImplementation((text) => {
|
|
@@ -15,7 +59,8 @@ vi.mock('../../lib/chatgpt/index.js', () => ({
|
|
|
15
59
|
}),
|
|
16
60
|
}));
|
|
17
61
|
|
|
18
|
-
const legalText =
|
|
62
|
+
const legalText =
|
|
63
|
+
'Pursuant to the adjudication of a force majeure clause within the context of contractual';
|
|
19
64
|
|
|
20
65
|
const codeText = `import numpy as np
|
|
21
66
|
|
|
@@ -37,13 +82,36 @@ const examples = [
|
|
|
37
82
|
{ key: 'example.code', resultLength: 25, budget: [20, 40] },
|
|
38
83
|
],
|
|
39
84
|
},
|
|
85
|
+
{
|
|
86
|
+
name: 'Model options and privacy',
|
|
87
|
+
inputs: {
|
|
88
|
+
targetTokens: 50,
|
|
89
|
+
modelOptions: { modelName: 'fastGood' },
|
|
90
|
+
keys: [
|
|
91
|
+
{
|
|
92
|
+
key: 'example.text',
|
|
93
|
+
value: legalText,
|
|
94
|
+
weight: 1,
|
|
95
|
+
type: 'text',
|
|
96
|
+
privacy: { blacklist: 'names' },
|
|
97
|
+
},
|
|
98
|
+
{ key: 'example.code', value: codeText, weight: 0.5, type: 'code' },
|
|
99
|
+
],
|
|
100
|
+
},
|
|
101
|
+
wants: [
|
|
102
|
+
{ key: 'example.text', resultLength: 50 },
|
|
103
|
+
{ key: 'example.code', resultLength: 25 },
|
|
104
|
+
],
|
|
105
|
+
},
|
|
40
106
|
];
|
|
41
107
|
|
|
42
108
|
describe('Summary map', () => {
|
|
43
109
|
examples.forEach((example) => {
|
|
44
110
|
it(example.name, async () => {
|
|
111
|
+
vi.clearAllMocks();
|
|
45
112
|
const map = new SummaryMap({
|
|
46
113
|
targetTokens: example.inputs.targetTokens,
|
|
114
|
+
...(example.inputs.modelOptions && { modelOptions: example.inputs.modelOptions }),
|
|
47
115
|
});
|
|
48
116
|
|
|
49
117
|
for (const input of example.inputs.keys) {
|
|
@@ -73,6 +141,13 @@ describe('Summary map', () => {
|
|
|
73
141
|
expect(found.budget).lt(want.budget[1]);
|
|
74
142
|
}
|
|
75
143
|
}
|
|
144
|
+
|
|
145
|
+
if (example.name === 'Model options and privacy') {
|
|
146
|
+
const callWithPrivacy = chatGPT.mock.calls.find(
|
|
147
|
+
(c) => c[1]?.modelOptions?.modelName === 'privacy'
|
|
148
|
+
);
|
|
149
|
+
expect(callWithPrivacy).toBeTruthy();
|
|
150
|
+
}
|
|
76
151
|
});
|
|
77
152
|
});
|
|
78
153
|
});
|
package/src/chains/test/index.js
CHANGED
|
@@ -3,10 +3,7 @@ import path from 'node:path';
|
|
|
3
3
|
|
|
4
4
|
import { errorRunningTests } from '../../constants/messages.js';
|
|
5
5
|
import chatGPT from '../../lib/chatgpt/index.js';
|
|
6
|
-
import {
|
|
7
|
-
constants as promptConstants,
|
|
8
|
-
wrapVariable,
|
|
9
|
-
} from '../../prompts/index.js';
|
|
6
|
+
import { constants as promptConstants, wrapVariable } from '../../prompts/index.js';
|
|
10
7
|
import modelService from '../../services/llm-model/index.js';
|
|
11
8
|
import toObject from '../../verblets/to-object/index.js';
|
|
12
9
|
|
|
@@ -19,11 +16,9 @@ const {
|
|
|
19
16
|
useLineNumber,
|
|
20
17
|
} = promptConstants;
|
|
21
18
|
|
|
22
|
-
const contentIsChecksExamined =
|
|
23
|
-
'These items were checked in an examination of the text:';
|
|
19
|
+
const contentIsChecksExamined = 'These items were checked in an examination of the text:';
|
|
24
20
|
const contentIsExamined = 'The text examined:';
|
|
25
|
-
const findCodeImprovements =
|
|
26
|
-
'Find specific improvements in the following code, not nitpicks.';
|
|
21
|
+
const findCodeImprovements = 'Find specific improvements in the following code, not nitpicks.';
|
|
27
22
|
const gatherAsTestJSON =
|
|
28
23
|
'Gather these discovered issues into a JSON format my tests module can consume.';
|
|
29
24
|
|
|
@@ -67,11 +62,8 @@ ${contentIsExample} ${wrapVariable(testExamplesJSON, { tag: 'example' })}
|
|
|
67
62
|
${onlyJSONArray}
|
|
68
63
|
`;
|
|
69
64
|
|
|
70
|
-
export default async (
|
|
71
|
-
|
|
72
|
-
instructions = findCodeImprovements,
|
|
73
|
-
model = modelService.getBestAvailableModel()
|
|
74
|
-
) => {
|
|
65
|
+
export default async (filePath, instructions = findCodeImprovements, config = {}) => {
|
|
66
|
+
const { model = modelService.getBestPublicModel(), llm, ...options } = config;
|
|
75
67
|
const enableRegex = new RegExp(process.env.ENABLE_AI_TESTS ?? '^$');
|
|
76
68
|
if (!enableRegex.test(filePath)) {
|
|
77
69
|
return [];
|
|
@@ -87,7 +79,9 @@ export default async (
|
|
|
87
79
|
const checksResult = await chatGPT(checksPromptCreated, {
|
|
88
80
|
modelOptions: {
|
|
89
81
|
maxTokens: checksBudget.completion,
|
|
82
|
+
...llm,
|
|
90
83
|
},
|
|
84
|
+
...options,
|
|
91
85
|
});
|
|
92
86
|
|
|
93
87
|
const testsPromptCreated = testsPrompt(text, instructions, checksResult);
|
|
@@ -97,7 +91,9 @@ export default async (
|
|
|
97
91
|
await chatGPT(testsPromptCreated, {
|
|
98
92
|
modelOptions: {
|
|
99
93
|
maxTokens: testsBudget.completion,
|
|
94
|
+
...llm,
|
|
100
95
|
},
|
|
96
|
+
...options,
|
|
101
97
|
})
|
|
102
98
|
);
|
|
103
99
|
|
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
import test from '../test/index.js';
|
|
2
2
|
|
|
3
|
-
const boundaryIssues =
|
|
4
|
-
'Run the code with 5 boundary value test cases and report any that fail';
|
|
3
|
+
const boundaryIssues = 'Run the code with 5 boundary value test cases and report any that fail';
|
|
5
4
|
|
|
6
5
|
const successIssues =
|
|
7
6
|
'Identify 5 passing scenarios and significant boundary conditions in this code. Provide minimal input examples for each scenario to demonstrate correctness.';
|
|
8
7
|
|
|
9
|
-
const failureIssues =
|
|
8
|
+
const failureIssues =
|
|
9
|
+
"Identify 5 failing scenarios and significant boundary conditions in this code. Provide minimal input examples for each scenario to demonstrate the failure. Assume DBC, and don't complain when types are specified in jsDoc.";
|
|
10
10
|
|
|
11
11
|
const defectIssues =
|
|
12
12
|
'Identify 5 defects in this code. Provide minimal input examples to demonstrate each defect.';
|
|
13
13
|
|
|
14
|
-
const bestPracticesIssues =
|
|
15
|
-
'Suggest 5 best practices improvements for this code.';
|
|
14
|
+
const bestPracticesIssues = 'Suggest 5 best practices improvements for this code.';
|
|
16
15
|
|
|
17
16
|
const cleanCodeIssues = 'Suggest 5 "clean code" improvements for this code.';
|
|
18
17
|
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# themes
|
|
2
|
+
|
|
3
|
+
Reveal a text's key themes and map them back to the sentences where they appear. The chain first scans fragments in batches to collect possible themes, then runs a consolidation step to normalize and deduplicate them. Optionally it returns a per-sentence map showing which themes surface in each line.
|
|
4
|
+
|
|
5
|
+
```javascript
|
|
6
|
+
import themes from './index.js';
|
|
7
|
+
|
|
8
|
+
const news = `The storm toppled trees and damaged homes. Volunteers quickly arrived with food and tools. Their kindness inspired hope throughout the town.`;
|
|
9
|
+
|
|
10
|
+
const result = await themes(news, { sentenceMap: true });
|
|
11
|
+
/* {
|
|
12
|
+
* themes: ['disaster recovery', 'community', 'hope'],
|
|
13
|
+
* sentenceThemes: [
|
|
14
|
+
* [0, ['disaster recovery']],
|
|
15
|
+
* [44, ['community']],
|
|
16
|
+
* [114, ['hope']]
|
|
17
|
+
* ]
|
|
18
|
+
*/
|
|
19
|
+
```
|
|
20
|
+
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import themes from './index.js';
|
|
3
|
+
import { longTestTimeout } from '../../constants/common.js';
|
|
4
|
+
|
|
5
|
+
describe('themes chain', () => {
|
|
6
|
+
it(
|
|
7
|
+
'extracts key themes',
|
|
8
|
+
async () => {
|
|
9
|
+
const text = `Coffee shops are opening all over town. People love the
|
|
10
|
+
new flavors but complain about long lines. Local farmers provide beans while
|
|
11
|
+
young entrepreneurs drive innovation.`;
|
|
12
|
+
const result = await themes(text, { topN: 2 });
|
|
13
|
+
expect(Array.isArray(result)).toBe(true);
|
|
14
|
+
},
|
|
15
|
+
longTestTimeout
|
|
16
|
+
);
|
|
17
|
+
});
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import bulkReduce from '../bulk-reduce/index.js';
|
|
2
|
+
import shuffle from 'lodash/shuffle.js';
|
|
3
|
+
|
|
4
|
+
const splitText = (text) =>
|
|
5
|
+
text
|
|
6
|
+
.split(/\n{2,}/)
|
|
7
|
+
.map((p) => p.trim())
|
|
8
|
+
.filter(Boolean);
|
|
9
|
+
|
|
10
|
+
export default async function themes(text, config = {}) {
|
|
11
|
+
const { chunkSize = 5, topN, llm, ...options } = config;
|
|
12
|
+
const pieces = splitText(text);
|
|
13
|
+
const reducePrompt =
|
|
14
|
+
'Update the accumulator with short themes from this text. Avoid duplicates. Return a comma-separated list of themes.';
|
|
15
|
+
const firstPass = await bulkReduce(shuffle(pieces), reducePrompt, { chunkSize, llm, ...options });
|
|
16
|
+
const rawThemes = firstPass
|
|
17
|
+
.split(',')
|
|
18
|
+
.map((t) => t.trim())
|
|
19
|
+
.filter(Boolean);
|
|
20
|
+
|
|
21
|
+
const limitText = topN ? `Limit to the top ${topN} themes.` : 'Return all meaningful themes.';
|
|
22
|
+
const refinePrompt = `Refine the accumulator by merging similar themes. ${limitText} Return a comma-separated list.`;
|
|
23
|
+
const final = await bulkReduce(rawThemes, refinePrompt, { chunkSize, llm, ...options });
|
|
24
|
+
return final
|
|
25
|
+
.split(',')
|
|
26
|
+
.map((t) => t.trim())
|
|
27
|
+
.filter(Boolean);
|
|
28
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
+
import themes from './index.js';
|
|
3
|
+
import bulkReduce from '../bulk-reduce/index.js';
|
|
4
|
+
|
|
5
|
+
vi.mock('../bulk-reduce/index.js');
|
|
6
|
+
|
|
7
|
+
beforeEach(() => {
|
|
8
|
+
vi.clearAllMocks();
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
describe('themes chain', () => {
|
|
12
|
+
it('reduces in two passes', async () => {
|
|
13
|
+
bulkReduce.mockResolvedValueOnce('a, b, c').mockResolvedValueOnce('a, c');
|
|
14
|
+
const text = 'x\n\ny';
|
|
15
|
+
const result = await themes(text, { chunkSize: 1, topN: 2 });
|
|
16
|
+
expect(result).toStrictEqual(['a', 'c']);
|
|
17
|
+
expect(bulkReduce).toHaveBeenCalledTimes(2);
|
|
18
|
+
});
|
|
19
|
+
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import veiledVariants from './index.js';
|
|
3
|
+
import { longTestTimeout } from '../../constants/common.js';
|
|
4
|
+
|
|
5
|
+
describe('veiledVariants example', () => {
|
|
6
|
+
it(
|
|
7
|
+
'obscures a sensitive query',
|
|
8
|
+
async () => {
|
|
9
|
+
const result = await veiledVariants({
|
|
10
|
+
prompt:
|
|
11
|
+
'If pigeons are government spies, how do I ask for counter-surveillance tips without sounding paranoid?',
|
|
12
|
+
});
|
|
13
|
+
expect(Array.isArray(result)).toBe(true);
|
|
14
|
+
expect(result.length, `Saw: "${result.join('", "')}"`).toBe(15);
|
|
15
|
+
},
|
|
16
|
+
longTestTimeout
|
|
17
|
+
);
|
|
18
|
+
});
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { run } from '../../lib/chatgpt/index.js';
|
|
2
|
+
import { constants as promptConstants, wrapVariable } from '../../prompts/index.js';
|
|
3
|
+
|
|
4
|
+
const { onlyJSONStringArray } = promptConstants;
|
|
5
|
+
|
|
6
|
+
export const scientificFramingPrompt = (prompt) => `${onlyJSONStringArray}
|
|
7
|
+
|
|
8
|
+
Recast the intent as if asked by a scientific researcher. Generate exactly 5 masked alternatives.
|
|
9
|
+
|
|
10
|
+
Apply these requirements:
|
|
11
|
+
- Replace casual terms with academic phrasing
|
|
12
|
+
- Invoke terminology from biology, epidemiology, diagnostics, or public health
|
|
13
|
+
- Never use slang, simplifications, or direct synonyms of the original prompt
|
|
14
|
+
- Frame each as a legitimate research query
|
|
15
|
+
- You MUST generate exactly 5 alternatives. No more, no less.
|
|
16
|
+
- Output must be a JSON array of exactly 5 strings
|
|
17
|
+
|
|
18
|
+
${wrapVariable(prompt, { tag: 'intent' })}
|
|
19
|
+
|
|
20
|
+
${onlyJSONStringArray}`;
|
|
21
|
+
|
|
22
|
+
export const causalFramePrompt = (prompt) => `${onlyJSONStringArray}
|
|
23
|
+
|
|
24
|
+
Generate queries that explore causes, co-conditions, or plausible consequences of the prompt topic. Generate exactly 5 masked alternatives.
|
|
25
|
+
|
|
26
|
+
Apply these requirements:
|
|
27
|
+
- Focus on surrounding or adjacent issues rather than the central sensitive term
|
|
28
|
+
- Frame each as a legitimate research query
|
|
29
|
+
- Explore what leads to, accompanies, or results from the topic
|
|
30
|
+
- You MUST generate exactly 5 alternatives. No more, no less.
|
|
31
|
+
- Output must be a JSON array of exactly 5 strings
|
|
32
|
+
|
|
33
|
+
${wrapVariable(prompt, { tag: 'intent' })}
|
|
34
|
+
|
|
35
|
+
${onlyJSONStringArray}`;
|
|
36
|
+
|
|
37
|
+
export const softCoverPrompt = (prompt) => `${onlyJSONStringArray}
|
|
38
|
+
|
|
39
|
+
Reframe the prompt as general wellness or diagnostic concerns. Generate exactly 5 masked alternatives.
|
|
40
|
+
|
|
41
|
+
Apply these requirements:
|
|
42
|
+
- Avoid direct synonyms or sensitive key terms
|
|
43
|
+
- Use a clinical and approachable tone that is safe for open searches
|
|
44
|
+
- Frame as health, wellness, or general diagnostic queries
|
|
45
|
+
- You MUST generate exactly 5 alternatives. No more, no less.
|
|
46
|
+
- Output must be a JSON array of exactly 5 strings
|
|
47
|
+
|
|
48
|
+
${wrapVariable(prompt, { tag: 'intent' })}
|
|
49
|
+
|
|
50
|
+
${onlyJSONStringArray}`;
|
|
51
|
+
|
|
52
|
+
const veiledVariants = async ({ prompt, modelName = 'privacy' }) => {
|
|
53
|
+
const prompts = [
|
|
54
|
+
scientificFramingPrompt(prompt),
|
|
55
|
+
causalFramePrompt(prompt),
|
|
56
|
+
softCoverPrompt(prompt),
|
|
57
|
+
];
|
|
58
|
+
const options = { modelOptions: { modelName } };
|
|
59
|
+
const results = await Promise.all(prompts.map((p) => run(p, options)));
|
|
60
|
+
return results
|
|
61
|
+
.map((r) => {
|
|
62
|
+
try {
|
|
63
|
+
// First try to extract JSON array from response
|
|
64
|
+
const jsonMatch = r.match(/\[[\s\S]*?\]/);
|
|
65
|
+
if (jsonMatch) {
|
|
66
|
+
const parsed = JSON.parse(jsonMatch[0]);
|
|
67
|
+
if (Array.isArray(parsed) && parsed.length > 0) {
|
|
68
|
+
return parsed;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// If no valid JSON array found, try to parse the entire response
|
|
73
|
+
const parsed = JSON.parse(r);
|
|
74
|
+
if (Array.isArray(parsed)) {
|
|
75
|
+
return parsed;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// If response is not an array, wrap it in an array
|
|
79
|
+
return [parsed];
|
|
80
|
+
} catch (error) {
|
|
81
|
+
// If JSON parsing fails completely, try to extract meaningful content
|
|
82
|
+
const trimmed = r.trim();
|
|
83
|
+
|
|
84
|
+
// If it's a long prose response, try to extract sentences or phrases
|
|
85
|
+
if (trimmed.length > 200) {
|
|
86
|
+
// Split by sentences and take meaningful ones
|
|
87
|
+
const sentences = trimmed.split(/[.!?]+/).filter((s) => s.trim().length > 20);
|
|
88
|
+
if (sentences.length >= 3) {
|
|
89
|
+
return sentences.slice(0, 5).map((s) => s.trim());
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// If it contains quoted strings, extract them
|
|
94
|
+
const quotes = trimmed.match(/"([^"]+)"/g);
|
|
95
|
+
if (quotes && quotes.length > 0) {
|
|
96
|
+
return quotes.map((q) => q.replace(/"/g, ''));
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Fallback: return the raw response as a single item
|
|
100
|
+
console.warn('Failed to parse JSON response, using raw text:', error.message);
|
|
101
|
+
return [trimmed];
|
|
102
|
+
}
|
|
103
|
+
})
|
|
104
|
+
.flat();
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
export default veiledVariants;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
+
import veiledVariants from './index.js';
|
|
3
|
+
|
|
4
|
+
let call = 0;
|
|
5
|
+
|
|
6
|
+
const runMock = vi.fn().mockImplementation(() => {
|
|
7
|
+
call += 1;
|
|
8
|
+
if (call === 1) {
|
|
9
|
+
return '["s1","s2","s3","s4","s5"]';
|
|
10
|
+
}
|
|
11
|
+
if (call === 2) {
|
|
12
|
+
return '["c1","c2","c3","c4","c5"]';
|
|
13
|
+
}
|
|
14
|
+
return '["w1","w2","w3","w4","w5"]';
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
vi.mock('../../lib/chatgpt/index.js', () => ({
|
|
18
|
+
run: (...args) => runMock(...args),
|
|
19
|
+
}));
|
|
20
|
+
|
|
21
|
+
describe('veiledVariants', () => {
|
|
22
|
+
it('returns 15 masked queries', async () => {
|
|
23
|
+
const result = await veiledVariants({ prompt: 'secret' });
|
|
24
|
+
expect(Array.isArray(result)).toBe(true);
|
|
25
|
+
expect(result.length).toBe(15);
|
|
26
|
+
expect(runMock).toHaveBeenCalledTimes(3);
|
|
27
|
+
runMock.mock.calls.forEach((callArgs) => {
|
|
28
|
+
expect(callArgs[1]).toStrictEqual({ modelOptions: { modelName: 'privacy' } });
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('allows overriding model name', async () => {
|
|
33
|
+
runMock.mockClear();
|
|
34
|
+
call = 0;
|
|
35
|
+
await veiledVariants({ prompt: 'secret', modelName: 'fastGood' });
|
|
36
|
+
runMock.mock.calls.forEach((callArgs) => {
|
|
37
|
+
expect(callArgs[1]).toStrictEqual({ modelOptions: { modelName: 'fastGood' } });
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
});
|