@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
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
|
|
2
|
+
import glossary from './index.js';
|
|
3
|
+
import aiExpect from '../../verblets/expect/index.js';
|
|
4
|
+
import { longTestTimeout } from '../../constants/common.js';
|
|
5
|
+
|
|
6
|
+
describe('glossary examples', () => {
|
|
7
|
+
// Set environment mode to 'none' for all tests to avoid throwing
|
|
8
|
+
const originalMode = process.env.LLM_EXPECT_MODE;
|
|
9
|
+
|
|
10
|
+
beforeAll(() => {
|
|
11
|
+
process.env.LLM_EXPECT_MODE = 'none';
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
afterAll(() => {
|
|
15
|
+
if (originalMode !== undefined) {
|
|
16
|
+
process.env.LLM_EXPECT_MODE = originalMode;
|
|
17
|
+
} else {
|
|
18
|
+
delete process.env.LLM_EXPECT_MODE;
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it(
|
|
23
|
+
'extracts terms from a science paragraph',
|
|
24
|
+
async () => {
|
|
25
|
+
const text = `The chef explained how umami develops through the Maillard reaction alongside sous-vide techniques.`;
|
|
26
|
+
const result = await glossary(text, { maxTerms: 2 });
|
|
27
|
+
|
|
28
|
+
expect(result.length).toBeGreaterThan(0);
|
|
29
|
+
expect(Array.isArray(result)).toBe(true);
|
|
30
|
+
|
|
31
|
+
// LLM assertion to validate that extracted terms are technical/complex
|
|
32
|
+
const areTermsTechnical = await aiExpect(
|
|
33
|
+
`From the text "${text}", these terms were extracted: ${result.join(', ')}`
|
|
34
|
+
).toSatisfy(
|
|
35
|
+
'Are these terms technical or complex enough that a casual reader might need definitions?',
|
|
36
|
+
{
|
|
37
|
+
message: `Expected extracted terms to be technical/complex, but got: ${result.join(
|
|
38
|
+
', '
|
|
39
|
+
)}`,
|
|
40
|
+
}
|
|
41
|
+
);
|
|
42
|
+
expect(
|
|
43
|
+
areTermsTechnical,
|
|
44
|
+
`Expected extracted terms to be technical/complex, but got: ${result.join(', ')}`
|
|
45
|
+
).toBe(true);
|
|
46
|
+
|
|
47
|
+
// LLM assertion to validate terms are relevant to the source text
|
|
48
|
+
const areTermsRelevant = await aiExpect(
|
|
49
|
+
`Original text: "${text}" | Extracted terms: ${result.join(', ')}`
|
|
50
|
+
).toSatisfy(
|
|
51
|
+
'Are all these extracted terms actually present or directly related to the original text?',
|
|
52
|
+
{
|
|
53
|
+
message: `Expected terms to be relevant to source text, but extracted: ${result.join(
|
|
54
|
+
', '
|
|
55
|
+
)} from: "${text}"`,
|
|
56
|
+
}
|
|
57
|
+
);
|
|
58
|
+
expect(
|
|
59
|
+
areTermsRelevant,
|
|
60
|
+
`Expected terms to be relevant to source text, but extracted: ${result.join(
|
|
61
|
+
', '
|
|
62
|
+
)} from: "${text}"`
|
|
63
|
+
).toBe(true);
|
|
64
|
+
|
|
65
|
+
// LLM assertion to validate term selection quality
|
|
66
|
+
const isGoodSelection = await aiExpect(
|
|
67
|
+
`For a cooking/culinary text, these terms were selected for a glossary: ${result.join(
|
|
68
|
+
', '
|
|
69
|
+
)}`
|
|
70
|
+
).toSatisfy(
|
|
71
|
+
'Are these appropriate terms for a culinary glossary that would help readers understand cooking concepts?',
|
|
72
|
+
{ message: `Expected appropriate culinary terms, but got: ${result.join(', ')}` }
|
|
73
|
+
);
|
|
74
|
+
expect(
|
|
75
|
+
isGoodSelection,
|
|
76
|
+
`Expected appropriate culinary terms, but got: ${result.join(', ')}`
|
|
77
|
+
).toBe(true);
|
|
78
|
+
},
|
|
79
|
+
longTestTimeout
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
it(
|
|
83
|
+
'handles technical documentation with multiple complex terms',
|
|
84
|
+
async () => {
|
|
85
|
+
const sourceText = `Our microservice architecture uses an API gateway for routing. Authentication is handled via OAuth 2.0 and JWT tokens. We also employ load balancing to distribute traffic.`;
|
|
86
|
+
const result = await glossary(sourceText, { maxTerms: 5 });
|
|
87
|
+
expect(result).toBeDefined();
|
|
88
|
+
expect(Array.isArray(result)).toBe(true);
|
|
89
|
+
expect(result.length).toBeGreaterThan(0);
|
|
90
|
+
// Check that the extracted terms cover the key technical concepts in the source text.
|
|
91
|
+
const keyConcepts = ['microservice', 'API gateway', 'OAuth', 'JWT', 'load balancing'];
|
|
92
|
+
const coverage = keyConcepts.every((concept) =>
|
|
93
|
+
result.some((term) => term.toLowerCase().includes(concept.toLowerCase()))
|
|
94
|
+
);
|
|
95
|
+
expect(coverage).toBe(true);
|
|
96
|
+
},
|
|
97
|
+
longTestTimeout
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
it(
|
|
101
|
+
'filters out common words and focuses on specialized terms',
|
|
102
|
+
async () => {
|
|
103
|
+
const text = `The quantum entanglement phenomenon occurs when particles become interconnected,
|
|
104
|
+
demonstrating superposition states that challenge classical physics understanding.
|
|
105
|
+
This behavior is fundamental to quantum computing applications.`;
|
|
106
|
+
|
|
107
|
+
const result = await glossary(text, { maxTerms: 4 });
|
|
108
|
+
|
|
109
|
+
expect(result.length).toBeGreaterThan(0);
|
|
110
|
+
|
|
111
|
+
// LLM assertion to ensure no common words are included
|
|
112
|
+
const noCommonWords = await aiExpect(
|
|
113
|
+
`These terms were selected for a glossary: ${result.join(', ')}`
|
|
114
|
+
).toSatisfy(
|
|
115
|
+
'Are all of these terms specialized/technical rather than common everyday words?',
|
|
116
|
+
{
|
|
117
|
+
message: `Expected only specialized/technical terms, but some may be common words: ${result.join(
|
|
118
|
+
', '
|
|
119
|
+
)}`,
|
|
120
|
+
}
|
|
121
|
+
);
|
|
122
|
+
expect(
|
|
123
|
+
noCommonWords,
|
|
124
|
+
`Expected only specialized/technical terms, but some may be common words: ${result.join(
|
|
125
|
+
', '
|
|
126
|
+
)}`
|
|
127
|
+
).toBe(true);
|
|
128
|
+
|
|
129
|
+
// LLM assertion for scientific accuracy
|
|
130
|
+
const scientificallyAccurate = await aiExpect(
|
|
131
|
+
`From a quantum physics text, these terms were extracted: ${result.join(', ')}`
|
|
132
|
+
).toSatisfy(
|
|
133
|
+
'Are these reasonable terms that relate to quantum physics or scientific concepts? They should be legitimate scientific terminology, even if not all are highly technical quantum physics terms.',
|
|
134
|
+
{
|
|
135
|
+
message: `Expected reasonable scientific terms related to quantum physics, but got: ${result.join(
|
|
136
|
+
', '
|
|
137
|
+
)}. Terms should be legitimate scientific concepts.`,
|
|
138
|
+
}
|
|
139
|
+
);
|
|
140
|
+
expect(
|
|
141
|
+
scientificallyAccurate,
|
|
142
|
+
`Expected reasonable scientific terms related to quantum physics, but got: ${result.join(
|
|
143
|
+
', '
|
|
144
|
+
)}. Terms should be legitimate scientific concepts.`
|
|
145
|
+
).toBe(true);
|
|
146
|
+
|
|
147
|
+
// LLM assertion for educational value
|
|
148
|
+
const educationalValue = await aiExpect(
|
|
149
|
+
`For someone learning about quantum physics, these glossary terms were provided: ${result.join(
|
|
150
|
+
', '
|
|
151
|
+
)}`
|
|
152
|
+
).toSatisfy(
|
|
153
|
+
'Would defining these terms be helpful for understanding the quantum physics concepts in the text? Focus on whether they contribute to comprehension rather than requiring perfect technical precision.',
|
|
154
|
+
{
|
|
155
|
+
message: `Expected terms that would help with understanding quantum physics concepts, but got: ${result.join(
|
|
156
|
+
', '
|
|
157
|
+
)}`,
|
|
158
|
+
}
|
|
159
|
+
);
|
|
160
|
+
expect(
|
|
161
|
+
educationalValue,
|
|
162
|
+
`Expected terms that would help with understanding quantum physics concepts, but got: ${result.join(
|
|
163
|
+
', '
|
|
164
|
+
)}`
|
|
165
|
+
).toBe(true);
|
|
166
|
+
},
|
|
167
|
+
longTestTimeout
|
|
168
|
+
);
|
|
169
|
+
|
|
170
|
+
it(
|
|
171
|
+
'handles empty or simple text appropriately',
|
|
172
|
+
async () => {
|
|
173
|
+
const simpleText = `The cat sat on the mat. It was a sunny day.`;
|
|
174
|
+
const result = await glossary(simpleText, { maxTerms: 3 });
|
|
175
|
+
|
|
176
|
+
// Should return empty array or very few terms for simple text
|
|
177
|
+
expect(Array.isArray(result)).toBe(true);
|
|
178
|
+
|
|
179
|
+
if (result.length > 0) {
|
|
180
|
+
// If any terms are returned, they should still be reasonable
|
|
181
|
+
const reasonableForSimpleText = await aiExpect(
|
|
182
|
+
`From simple text "${simpleText}", these terms were extracted: ${result.join(', ')}`
|
|
183
|
+
).toSatisfy(
|
|
184
|
+
'If any terms were extracted from this simple text, are they reasonable choices?',
|
|
185
|
+
{
|
|
186
|
+
message: `Expected reasonable terms for simple text, but extracted: ${result.join(
|
|
187
|
+
', '
|
|
188
|
+
)} from: "${simpleText}"`,
|
|
189
|
+
}
|
|
190
|
+
);
|
|
191
|
+
expect(
|
|
192
|
+
reasonableForSimpleText,
|
|
193
|
+
`Expected reasonable terms for simple text, but extracted: ${result.join(
|
|
194
|
+
', '
|
|
195
|
+
)} from: "${simpleText}"`
|
|
196
|
+
).toBe(true);
|
|
197
|
+
} else {
|
|
198
|
+
// LLM assertion that empty result is appropriate for simple text
|
|
199
|
+
const appropriatelyEmpty = await aiExpect(
|
|
200
|
+
`For the simple text "${simpleText}", no glossary terms were extracted`
|
|
201
|
+
).toSatisfy(
|
|
202
|
+
'Is it appropriate to extract no glossary terms from this simple, everyday text?',
|
|
203
|
+
{ message: `Expected empty result to be appropriate for simple text: "${simpleText}"` }
|
|
204
|
+
);
|
|
205
|
+
expect(
|
|
206
|
+
appropriatelyEmpty,
|
|
207
|
+
`Expected empty result to be appropriate for simple text: "${simpleText}"`
|
|
208
|
+
).toBe(true);
|
|
209
|
+
}
|
|
210
|
+
},
|
|
211
|
+
longTestTimeout
|
|
212
|
+
);
|
|
213
|
+
|
|
214
|
+
it(
|
|
215
|
+
'extracts operative philosophical terms for conceptual clarity',
|
|
216
|
+
async () => {
|
|
217
|
+
const philosophyText = `Heidegger's concept of Dasein fundamentally challenges the Cartesian subject-object distinction
|
|
218
|
+
through his analysis of Being-in-the-world. The phenomenological reduction, as developed by Husserl,
|
|
219
|
+
brackets the natural attitude to reveal the intentional structure of consciousness. This hermeneutic circle
|
|
220
|
+
demonstrates how our pre-understanding shapes interpretation, while the ontological difference between
|
|
221
|
+
beings and Being itself remains concealed in everyday thrownness. Gadamer's fusion of horizons extends
|
|
222
|
+
this analysis to show how tradition and prejudice constitute the productive ground of understanding.`;
|
|
223
|
+
|
|
224
|
+
const result = await glossary(philosophyText, { maxTerms: 8 });
|
|
225
|
+
|
|
226
|
+
expect(result.length).toBeGreaterThan(0);
|
|
227
|
+
expect(result.length).toBeLessThanOrEqual(8);
|
|
228
|
+
|
|
229
|
+
// LLM assertion for philosophical term appropriateness - abstract concepts
|
|
230
|
+
const arePhilosophicalConcepts = await aiExpect(
|
|
231
|
+
`From philosophical text, these terms were extracted: ${result.join(', ')}`
|
|
232
|
+
).toSatisfy(
|
|
233
|
+
'Are these terms that would genuinely benefit from precise definition to avoid misunderstanding or ambiguity in philosophical discourse?'
|
|
234
|
+
);
|
|
235
|
+
expect(arePhilosophicalConcepts).toBe(true);
|
|
236
|
+
|
|
237
|
+
// LLM assertion for conceptual precision - terms that need clarification
|
|
238
|
+
const needDefinition = await aiExpect(
|
|
239
|
+
`These philosophical terms: ${result.join(', ')}`
|
|
240
|
+
).toSatisfy(
|
|
241
|
+
'Are these terms that would genuinely benefit from precise definition to avoid misunderstanding or ambiguity in philosophical discourse?',
|
|
242
|
+
{
|
|
243
|
+
message: `Expected terms needing precise definition for clarity, but got: ${result.join(
|
|
244
|
+
', '
|
|
245
|
+
)}`,
|
|
246
|
+
}
|
|
247
|
+
);
|
|
248
|
+
expect(
|
|
249
|
+
needDefinition,
|
|
250
|
+
`Expected terms needing precise definition for clarity, but got: ${result.join(', ')}`
|
|
251
|
+
).toBe(true);
|
|
252
|
+
|
|
253
|
+
// LLM assertion for operative significance - terms central to the argument
|
|
254
|
+
const operativeTerms = await aiExpect(
|
|
255
|
+
`In the context of phenomenology and hermeneutics, these terms were selected: ${result.join(
|
|
256
|
+
', '
|
|
257
|
+
)}`
|
|
258
|
+
).toSatisfy(
|
|
259
|
+
'Are these terms operatively significant - meaning they carry specific technical weight and are central to understanding the philosophical arguments being made?'
|
|
260
|
+
);
|
|
261
|
+
expect(operativeTerms).toBe(true);
|
|
262
|
+
|
|
263
|
+
// LLM assertion for avoiding common words - focus on technical terminology
|
|
264
|
+
const avoidCommonPhilosophical = await aiExpect(
|
|
265
|
+
`These terms from philosophical text: ${result.join(', ')}`
|
|
266
|
+
).toSatisfy(
|
|
267
|
+
'Are these specialized philosophical terms rather than common words that happen to appear in philosophical contexts?'
|
|
268
|
+
);
|
|
269
|
+
expect(avoidCommonPhilosophical).toBe(true);
|
|
270
|
+
},
|
|
271
|
+
longTestTimeout
|
|
272
|
+
);
|
|
273
|
+
|
|
274
|
+
it(
|
|
275
|
+
'extracts operative tech terms across multiple categories',
|
|
276
|
+
async () => {
|
|
277
|
+
const techText = `The team implemented Domain-Driven Design using the Repository pattern and CQRS architecture.
|
|
278
|
+
Martin Fowler's Strangler Fig pattern helped migrate the legacy system while Kent Beck's Test-Driven Development
|
|
279
|
+
approach ensured code quality. We used Docker containers orchestrated by Kubernetes, with Redis for caching
|
|
280
|
+
and PostgreSQL for persistence. The CI/CD pipeline leveraged Jenkins and implemented the Blue-Green deployment
|
|
281
|
+
strategy. Uncle Bob's Clean Architecture principles guided the service boundaries, while Eric Evans'
|
|
282
|
+
Bounded Context concept helped define microservice boundaries. The team followed Scrum methodology with
|
|
283
|
+
pair programming sessions.`;
|
|
284
|
+
|
|
285
|
+
const result = await glossary(techText, {
|
|
286
|
+
maxTerms: 12,
|
|
287
|
+
sortBy:
|
|
288
|
+
'importance for understanding the content, prioritizing concrete tools and technologies (Docker, Kubernetes, Redis, PostgreSQL, Jenkins) equally with architectural patterns and methodologies',
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
expect(result.length).toBeGreaterThan(0);
|
|
292
|
+
expect(result.length).toBeLessThanOrEqual(12);
|
|
293
|
+
|
|
294
|
+
// LLM assertion for technical tools identification
|
|
295
|
+
const includesTools = await aiExpect(
|
|
296
|
+
`From tech text, these terms were extracted: ${result.join(', ')}`
|
|
297
|
+
).toSatisfy(
|
|
298
|
+
'Do these terms include technical tools, technologies, or software systems (like Docker, Kubernetes, Redis, PostgreSQL, Jenkins)?',
|
|
299
|
+
{
|
|
300
|
+
message: `Expected to include technical tools/technologies, but got: ${result.join(
|
|
301
|
+
', '
|
|
302
|
+
)}`,
|
|
303
|
+
}
|
|
304
|
+
);
|
|
305
|
+
expect(
|
|
306
|
+
includesTools,
|
|
307
|
+
`Expected to include technical tools/technologies, but got: ${result.join(', ')}`
|
|
308
|
+
).toBe(true);
|
|
309
|
+
|
|
310
|
+
// LLM assertion for design patterns identification
|
|
311
|
+
const includesPatterns = await aiExpect(
|
|
312
|
+
`These terms from software development: ${result.join(', ')}`
|
|
313
|
+
).toSatisfy(
|
|
314
|
+
'Do these terms include software design patterns, architectural patterns, or development patterns (like Repository, CQRS, Strangler Fig, Blue-Green)?',
|
|
315
|
+
{
|
|
316
|
+
message: `Expected to include design/architectural patterns, but got: ${result.join(
|
|
317
|
+
', '
|
|
318
|
+
)}`,
|
|
319
|
+
}
|
|
320
|
+
);
|
|
321
|
+
expect(
|
|
322
|
+
includesPatterns,
|
|
323
|
+
`Expected to include design/architectural patterns, but got: ${result.join(', ')}`
|
|
324
|
+
).toBe(true);
|
|
325
|
+
|
|
326
|
+
// LLM assertion for methodologies and practices
|
|
327
|
+
const includesMethodologies = await aiExpect(
|
|
328
|
+
`From development context, these terms: ${result.join(', ')}`
|
|
329
|
+
).toSatisfy(
|
|
330
|
+
'Do these terms include software development methodologies, practices, or approaches (like Domain-Driven Design, Test-Driven Development, Clean Architecture, Scrum)?',
|
|
331
|
+
{
|
|
332
|
+
message: `Expected to include development methodologies/practices, but got: ${result.join(
|
|
333
|
+
', '
|
|
334
|
+
)}`,
|
|
335
|
+
}
|
|
336
|
+
);
|
|
337
|
+
expect(
|
|
338
|
+
includesMethodologies,
|
|
339
|
+
`Expected to include development methodologies/practices, but got: ${result.join(', ')}`
|
|
340
|
+
).toBe(true);
|
|
341
|
+
|
|
342
|
+
// LLM assertion for key people/thought leaders (optional but valuable)
|
|
343
|
+
const mayIncludePeople = await aiExpect(`These tech terms: ${result.join(', ')}`).toSatisfy(
|
|
344
|
+
'Do these terms appropriately focus on concepts, tools, and patterns rather than just including person names, while potentially including key thought leaders if they are central to understanding specific methodologies?',
|
|
345
|
+
{
|
|
346
|
+
message: `Expected focus on concepts/tools over person names, but got: ${result.join(
|
|
347
|
+
', '
|
|
348
|
+
)}`,
|
|
349
|
+
}
|
|
350
|
+
);
|
|
351
|
+
expect(
|
|
352
|
+
mayIncludePeople,
|
|
353
|
+
`Expected focus on concepts/tools over person names, but got: ${result.join(', ')}`
|
|
354
|
+
).toBe(true);
|
|
355
|
+
|
|
356
|
+
// LLM assertion for operative significance in tech context
|
|
357
|
+
const operativeTechTerms = await aiExpect(
|
|
358
|
+
`In a software development context, these terms: ${result.join(', ')}`
|
|
359
|
+
).toSatisfy(
|
|
360
|
+
'Are these terms operatively significant for understanding the technical architecture, development practices, and implementation decisions being described?',
|
|
361
|
+
{ message: `Expected operatively significant tech terms, but got: ${result.join(', ')}` }
|
|
362
|
+
);
|
|
363
|
+
expect(
|
|
364
|
+
operativeTechTerms,
|
|
365
|
+
`Expected operatively significant tech terms, but got: ${result.join(', ')}`
|
|
366
|
+
).toBe(true);
|
|
367
|
+
|
|
368
|
+
// LLM assertion for practical utility - terms that need definition
|
|
369
|
+
const practicalUtility = await aiExpect(
|
|
370
|
+
`For someone learning about software architecture and development, these terms: ${result.join(
|
|
371
|
+
', '
|
|
372
|
+
)}`
|
|
373
|
+
).toSatisfy(
|
|
374
|
+
'Are these terms that would genuinely benefit from clear definitions to understand modern software development practices and architectural decisions?',
|
|
375
|
+
{
|
|
376
|
+
message: `Expected terms needing definition for learning, but got: ${result.join(', ')}`,
|
|
377
|
+
}
|
|
378
|
+
);
|
|
379
|
+
expect(
|
|
380
|
+
practicalUtility,
|
|
381
|
+
`Expected terms needing definition for learning, but got: ${result.join(', ')}`
|
|
382
|
+
).toBe(true);
|
|
383
|
+
},
|
|
384
|
+
longTestTimeout
|
|
385
|
+
);
|
|
386
|
+
});
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import nlp from 'compromise';
|
|
2
|
+
import sort from '../sort/index.js';
|
|
3
|
+
import { bulkMapRetry } from '../bulk-map/index.js';
|
|
4
|
+
import { constants as promptConstants } from '../../prompts/index.js';
|
|
5
|
+
import parseLLMList from '../../lib/parse-llm-list/index.js';
|
|
6
|
+
|
|
7
|
+
const { onlyJSONStringArrayPerLine } = promptConstants;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Extract uncommon or technical terms from text that would benefit from definition.
|
|
11
|
+
*
|
|
12
|
+
* @param {string} text - source text
|
|
13
|
+
* @param {object} [options]
|
|
14
|
+
* @param {number} [options.maxTerms=10] - maximum terms to return
|
|
15
|
+
* @param {number} [options.batchSize=3] - number of sentences per batch
|
|
16
|
+
* @param {number} [options.overlap=1] - number of overlapping sentences between batches
|
|
17
|
+
* @param {number} [options.chunkSize=1] - number of text chunks to process in parallel
|
|
18
|
+
* @param {string} [options.sortBy='importance for understanding the content'] - sorting criteria
|
|
19
|
+
* @returns {Promise<string[]>} list of important terms, sorted by relevance
|
|
20
|
+
*/
|
|
21
|
+
export default async function glossary(
|
|
22
|
+
text,
|
|
23
|
+
{
|
|
24
|
+
maxTerms = 10,
|
|
25
|
+
batchSize = 3,
|
|
26
|
+
overlap = 1,
|
|
27
|
+
chunkSize = 1,
|
|
28
|
+
sortBy = 'importance for understanding the content',
|
|
29
|
+
} = {}
|
|
30
|
+
) {
|
|
31
|
+
if (!text || !text.trim()) return [];
|
|
32
|
+
|
|
33
|
+
// Parse sentences using compromise
|
|
34
|
+
const doc = nlp(text);
|
|
35
|
+
const sentences = doc.sentences().out('array');
|
|
36
|
+
|
|
37
|
+
if (sentences.length === 0) return [];
|
|
38
|
+
|
|
39
|
+
// Create batches of sentences with overlap
|
|
40
|
+
const textChunks = [];
|
|
41
|
+
for (let i = 0; i < sentences.length; i += batchSize - overlap) {
|
|
42
|
+
const batch = sentences.slice(i, i + batchSize);
|
|
43
|
+
if (batch.length > 0) {
|
|
44
|
+
textChunks.push(batch.join(' '));
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const instructions = `For each text chunk, extract specialized terms that would benefit from definition in a glossary.
|
|
49
|
+
|
|
50
|
+
Focus on terms that:
|
|
51
|
+
- Are technical, academic, or domain-specific
|
|
52
|
+
- Would be unfamiliar to a general audience
|
|
53
|
+
- Carry precise meaning in their field
|
|
54
|
+
- Are essential for understanding the content
|
|
55
|
+
|
|
56
|
+
${onlyJSONStringArrayPerLine}`;
|
|
57
|
+
|
|
58
|
+
const mapped = await bulkMapRetry(textChunks, instructions, { chunkSize });
|
|
59
|
+
|
|
60
|
+
const termSet = new Set();
|
|
61
|
+
mapped.forEach((line) => {
|
|
62
|
+
const terms = parseLLMList(line);
|
|
63
|
+
terms.forEach((term) => {
|
|
64
|
+
termSet.add(term);
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
const terms = Array.from(termSet);
|
|
69
|
+
if (terms.length === 0) return [];
|
|
70
|
+
|
|
71
|
+
// Sort by importance for understanding the content
|
|
72
|
+
const sorted = await sort(terms, sortBy);
|
|
73
|
+
|
|
74
|
+
return sorted.slice(0, maxTerms);
|
|
75
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
2
|
+
import glossary from './index.js';
|
|
3
|
+
|
|
4
|
+
vi.mock('../bulk-map/index.js', () => ({
|
|
5
|
+
bulkMapRetry: vi.fn(() => Promise.resolve(['qubits, entanglement', 'decoherence, qubits'])),
|
|
6
|
+
default: vi.fn(),
|
|
7
|
+
}));
|
|
8
|
+
|
|
9
|
+
vi.mock('../sort/index.js', () => ({
|
|
10
|
+
default: vi.fn((list, _criteria, _config) => Promise.resolve(list)),
|
|
11
|
+
}));
|
|
12
|
+
|
|
13
|
+
describe('glossary', () => {
|
|
14
|
+
it('collects unique terms', async () => {
|
|
15
|
+
const text = 'para1\n\npara2';
|
|
16
|
+
const result = await glossary(text, { maxTerms: 5 });
|
|
17
|
+
expect(result).toStrictEqual(['qubits', 'entanglement', 'decoherence']);
|
|
18
|
+
});
|
|
19
|
+
});
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# Intersections Chain
|
|
2
|
+
|
|
3
|
+
The intersections chain finds comprehensive intersections for all combinations of items, ensuring consistent and exhaustive results through example-driven improvement with built-in quality validation.
|
|
4
|
+
|
|
5
|
+
## Real-World Example: Planning a Perfect Weekend
|
|
6
|
+
|
|
7
|
+
Imagine you're planning activities that work for different groups of people. Let's find intersections between "outdoor enthusiasts", "food lovers", and "budget-conscious friends":
|
|
8
|
+
|
|
9
|
+
```javascript
|
|
10
|
+
import intersections from './index.js';
|
|
11
|
+
|
|
12
|
+
const result = await intersections([
|
|
13
|
+
'outdoor enthusiasts',
|
|
14
|
+
'food lovers',
|
|
15
|
+
'budget-conscious friends'
|
|
16
|
+
]);
|
|
17
|
+
|
|
18
|
+
console.log(result);
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
**Sample Output:**
|
|
22
|
+
```javascript
|
|
23
|
+
{
|
|
24
|
+
"outdoor enthusiasts + food lovers": {
|
|
25
|
+
combination: ["outdoor enthusiasts", "food lovers"],
|
|
26
|
+
description: "Activities that combine outdoor adventure with culinary experiences",
|
|
27
|
+
elements: [
|
|
28
|
+
"camping with gourmet cooking",
|
|
29
|
+
"food truck festivals in parks",
|
|
30
|
+
"farmers market visits",
|
|
31
|
+
"outdoor barbecue competitions",
|
|
32
|
+
"hiking to scenic picnic spots",
|
|
33
|
+
"beach cookouts",
|
|
34
|
+
"food foraging tours"
|
|
35
|
+
]
|
|
36
|
+
},
|
|
37
|
+
"outdoor enthusiasts + budget-conscious friends": {
|
|
38
|
+
combination: ["outdoor enthusiasts", "budget-conscious friends"],
|
|
39
|
+
description: "Affordable outdoor activities that don't break the bank",
|
|
40
|
+
elements: [
|
|
41
|
+
"free hiking trails",
|
|
42
|
+
"public beach visits",
|
|
43
|
+
"city park activities",
|
|
44
|
+
"free outdoor concerts",
|
|
45
|
+
"community garden volunteering",
|
|
46
|
+
"geocaching adventures",
|
|
47
|
+
"sunset watching spots"
|
|
48
|
+
]
|
|
49
|
+
},
|
|
50
|
+
"food lovers + budget-conscious friends": {
|
|
51
|
+
combination: ["food lovers", "budget-conscious friends"],
|
|
52
|
+
description: "Delicious food experiences that are wallet-friendly",
|
|
53
|
+
elements: [
|
|
54
|
+
"happy hour specials",
|
|
55
|
+
"food truck meals",
|
|
56
|
+
"potluck dinner parties",
|
|
57
|
+
"cooking classes at community centers",
|
|
58
|
+
"ethnic food markets",
|
|
59
|
+
"restaurant week deals",
|
|
60
|
+
"home cooking challenges"
|
|
61
|
+
]
|
|
62
|
+
},
|
|
63
|
+
"outdoor enthusiasts + food lovers + budget-conscious friends": {
|
|
64
|
+
combination: ["outdoor enthusiasts", "food lovers", "budget-conscious friends"],
|
|
65
|
+
description: "Perfect activities that satisfy adventure, food, and budget needs",
|
|
66
|
+
elements: [
|
|
67
|
+
"picnic in free parks with homemade food",
|
|
68
|
+
"food truck festivals in public spaces",
|
|
69
|
+
"community garden potlucks",
|
|
70
|
+
"beach barbecues with shared costs",
|
|
71
|
+
"hiking with packed gourmet sandwiches",
|
|
72
|
+
"free outdoor farmers markets"
|
|
73
|
+
]
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## How it Works
|
|
79
|
+
|
|
80
|
+
1. **Generate Combinations** - Creates all possible combinations of the input items (including single items)
|
|
81
|
+
2. **Shuffle & Score** - Randomly orders combinations and uses AI to score quality (1-10 scale)
|
|
82
|
+
3. **Find Best Examples** - Identifies the first 3 combinations that score above the threshold
|
|
83
|
+
4. **Validate Examples** - Ensures the top examples are high-quality intersections
|
|
84
|
+
5. **Improve All Results** - Uses the best examples as patterns to enhance all intersection results
|
|
85
|
+
6. **Error Handling** - Throws an error if no combinations meet the quality threshold
|
|
86
|
+
|
|
87
|
+
This approach finds good examples organically, uses them to improve the quality of all results, and validates quality at key checkpoints.
|
|
88
|
+
|
|
89
|
+
## API Reference
|
|
90
|
+
|
|
91
|
+
### `intersections(items, options)`
|
|
92
|
+
|
|
93
|
+
**Parameters:**
|
|
94
|
+
- `items` (Array): Array of items to find intersections between
|
|
95
|
+
- `options` (Object, optional): Configuration options
|
|
96
|
+
- `instructions` (string): Custom instructions for intersection finding
|
|
97
|
+
- `minSize` (number, default: 1): Minimum combination size
|
|
98
|
+
- `maxSize` (number, default: items.length): Maximum combination size
|
|
99
|
+
- `batchSize` (number, default: 5): Number of combinations to process in parallel
|
|
100
|
+
- `goodnessScore` (number, default: 7): Minimum score threshold for good examples (1-10 scale)
|
|
101
|
+
|
|
102
|
+
**Returns:** Object with intersection results
|
|
103
|
+
|
|
104
|
+
**Throws:** Error when no combinations score above the goodness threshold
|
|
105
|
+
|
|
106
|
+
### Usage Examples
|
|
107
|
+
|
|
108
|
+
```javascript
|
|
109
|
+
// Basic usage
|
|
110
|
+
const results = await intersections(['cats', 'dogs', 'birds']);
|
|
111
|
+
|
|
112
|
+
// Custom configuration
|
|
113
|
+
const results = await intersections(['hiking', 'photography', 'meditation'], {
|
|
114
|
+
instructions: 'Focus on peaceful, mindful activities',
|
|
115
|
+
batchSize: 10, // Process more combinations in parallel
|
|
116
|
+
goodnessScore: 8, // Higher quality threshold
|
|
117
|
+
minSize: 2, // Only combinations of 2+ items
|
|
118
|
+
maxSize: 3 // Maximum 3 items per combination
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
// Error handling
|
|
122
|
+
try {
|
|
123
|
+
const results = await intersections(['incompatible', 'categories'], {
|
|
124
|
+
goodnessScore: 9 // Very high threshold
|
|
125
|
+
});
|
|
126
|
+
} catch (error) {
|
|
127
|
+
console.log(error.message);
|
|
128
|
+
// "No intersections found with score above 9. Consider lowering the goodnessScore threshold or improving input quality."
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## Configuration Tips
|
|
133
|
+
|
|
134
|
+
- **Lower `goodnessScore`** (5-6) for more permissive quality standards
|
|
135
|
+
- **Higher `goodnessScore`** (8-9) for stricter quality requirements
|
|
136
|
+
- **Increase `batchSize`** (10-15) for faster processing with good API limits
|
|
137
|
+
- **Decrease `batchSize`** (2-3) to be gentler on API rate limits
|
|
138
|
+
- **Use `instructions`** to guide the AI toward specific types of intersections
|
|
139
|
+
|
|
140
|
+
## Quality Assurance
|
|
141
|
+
|
|
142
|
+
The chain includes built-in quality validation:
|
|
143
|
+
|
|
144
|
+
- **Example Validation**: Ensures the top 3 examples have meaningful descriptions, good element counts, and represent quality intersections
|
|
145
|
+
- **Error Handling**: Throws descriptive errors when quality thresholds aren't met
|
|
146
|
+
- **Parallel Processing**: Efficiently processes combinations in configurable batches
|
|
147
|
+
|
|
148
|
+
The system learns from its best results and applies those patterns to enhance the quality of all intersections, moving away from predefined categorization methods.
|
|
149
|
+
|
|
150
|
+
## Usage
|
|
151
|
+
|
|
152
|
+
```javascript
|