@far-world-labs/verblets 0.1.7 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +86 -213
- package/dist/index.browser.js +74 -0
- package/dist/index.js +548 -0
- package/dist/shared-C6kPWghF.js +7806 -0
- package/package.json +32 -8
- package/.cursor/launch.json +0 -30
- package/.cursor/settings.json +0 -20
- package/.github/workflows/branch-protection.yml +0 -22
- package/.github/workflows/ci.yml +0 -165
- package/.husky/pre-commit +0 -4
- package/.prettierrc +0 -6
- package/.release-it.json +0 -12
- package/.vitest.config.examples.js +0 -8
- package/.vitest.config.js +0 -8
- package/.vscode/launch.json +0 -31
- package/AGENTS.md +0 -220
- package/DEVELOPING.md +0 -105
- package/docker-compose.yml +0 -7
- package/eslint.config.js +0 -80
- package/scripts/generate-chain/index.js +0 -111
- package/scripts/generate-lib/index.js +0 -68
- package/scripts/generate-test/index.js +0 -137
- package/scripts/generate-verblet/README.md +0 -17
- package/scripts/generate-verblet/index.js +0 -110
- package/scripts/run.sh +0 -15
- package/scripts/runner/index.js +0 -56
- package/scripts/simple-editor/README.md +0 -34
- package/scripts/simple-editor/index.js +0 -79
- package/scripts/summarize-files/index.js +0 -70
- package/src/chains/README.md +0 -30
- package/src/chains/anonymize/README.md +0 -21
- package/src/chains/anonymize/index.examples.js +0 -75
- package/src/chains/anonymize/index.js +0 -121
- package/src/chains/anonymize/index.spec.js +0 -78
- package/src/chains/bulk-central-tendency/index.examples.js +0 -138
- package/src/chains/bulk-central-tendency/index.js +0 -91
- package/src/chains/bulk-filter/README.md +0 -21
- package/src/chains/bulk-filter/index.examples.js +0 -22
- package/src/chains/bulk-filter/index.js +0 -58
- package/src/chains/bulk-filter/index.spec.js +0 -38
- package/src/chains/bulk-find/README.md +0 -16
- package/src/chains/bulk-find/index.examples.js +0 -20
- package/src/chains/bulk-find/index.js +0 -30
- package/src/chains/bulk-find/index.spec.js +0 -26
- package/src/chains/bulk-group/README.md +0 -23
- package/src/chains/bulk-group/index.examples.js +0 -18
- package/src/chains/bulk-group/index.js +0 -34
- package/src/chains/bulk-group/index.spec.js +0 -41
- package/src/chains/bulk-map/README.md +0 -43
- package/src/chains/bulk-map/index.examples.js +0 -17
- package/src/chains/bulk-map/index.js +0 -86
- package/src/chains/bulk-map/index.spec.js +0 -44
- package/src/chains/bulk-reduce/README.md +0 -12
- package/src/chains/bulk-reduce/index.examples.js +0 -15
- package/src/chains/bulk-reduce/index.js +0 -13
- package/src/chains/bulk-reduce/index.spec.js +0 -25
- package/src/chains/bulk-score/README.md +0 -16
- package/src/chains/bulk-score/bulk-score-result.json +0 -18
- package/src/chains/bulk-score/index.examples.js +0 -22
- package/src/chains/bulk-score/index.js +0 -133
- package/src/chains/bulk-score/index.spec.js +0 -30
- package/src/chains/category-samples/README.md +0 -61
- package/src/chains/category-samples/index.examples.js +0 -103
- package/src/chains/category-samples/index.js +0 -134
- package/src/chains/collect-terms/README.md +0 -12
- package/src/chains/collect-terms/index.examples.js +0 -16
- package/src/chains/collect-terms/index.js +0 -44
- package/src/chains/collect-terms/index.spec.js +0 -25
- package/src/chains/date/README.md +0 -12
- package/src/chains/date/index.examples.js +0 -47
- package/src/chains/date/index.js +0 -74
- package/src/chains/date/index.spec.js +0 -62
- package/src/chains/disambiguate/README.md +0 -22
- package/src/chains/disambiguate/disambiguate-meanings-result.json +0 -16
- package/src/chains/disambiguate/index.examples.js +0 -18
- package/src/chains/disambiguate/index.js +0 -92
- package/src/chains/disambiguate/index.spec.js +0 -25
- package/src/chains/dismantle/README.md +0 -67
- package/src/chains/dismantle/dismantle.examples.js +0 -27
- package/src/chains/dismantle/index.examples.js +0 -30
- package/src/chains/dismantle/index.js +0 -303
- package/src/chains/dismantle/index.spec.js +0 -32
- package/src/chains/expect/README.md +0 -171
- package/src/chains/expect/index.examples.js +0 -146
- package/src/chains/expect/index.js +0 -173
- package/src/chains/expect/index.spec.js +0 -324
- package/src/chains/filter-ambiguous/README.md +0 -11
- package/src/chains/filter-ambiguous/index.examples.js +0 -20
- package/src/chains/filter-ambiguous/index.js +0 -49
- package/src/chains/filter-ambiguous/index.spec.js +0 -31
- package/src/chains/glossary/README.md +0 -19
- package/src/chains/glossary/index.examples.js +0 -386
- package/src/chains/glossary/index.js +0 -75
- package/src/chains/glossary/index.spec.js +0 -19
- package/src/chains/intersections/README.md +0 -152
- package/src/chains/intersections/index.examples.js +0 -279
- package/src/chains/intersections/index.js +0 -366
- package/src/chains/intersections/intersection-result.json +0 -38
- package/src/chains/list/index.examples.js +0 -68
- package/src/chains/list/index.js +0 -214
- package/src/chains/list/index.spec.js +0 -67
- package/src/chains/list/list-result.json +0 -16
- package/src/chains/list/schema.json +0 -24
- package/src/chains/llm-logger/README.md +0 -208
- package/src/chains/llm-logger/index.js +0 -205
- package/src/chains/llm-logger/index.spec.js +0 -330
- package/src/chains/questions/index.examples.js +0 -69
- package/src/chains/questions/index.js +0 -135
- package/src/chains/questions/index.spec.js +0 -29
- package/src/chains/scan-js/index.js +0 -116
- package/src/chains/set-interval/README.md +0 -81
- package/src/chains/set-interval/index.examples.js +0 -36
- package/src/chains/set-interval/index.js +0 -131
- package/src/chains/set-interval/index.spec.js +0 -70
- package/src/chains/socratic/README.md +0 -17
- package/src/chains/socratic/index.js +0 -64
- package/src/chains/socratic/index.spec.js +0 -24
- package/src/chains/sort/index.examples.js +0 -36
- package/src/chains/sort/index.js +0 -163
- package/src/chains/sort/index.spec.js +0 -112
- package/src/chains/sort/sort-result.json +0 -16
- package/src/chains/summary-map/README.md +0 -41
- package/src/chains/summary-map/index.examples.js +0 -64
- package/src/chains/summary-map/index.js +0 -226
- package/src/chains/summary-map/index.spec.js +0 -153
- package/src/chains/test/index.js +0 -114
- package/src/chains/test-advice/index.js +0 -35
- package/src/chains/themes/README.md +0 -20
- package/src/chains/themes/index.examples.js +0 -17
- package/src/chains/themes/index.js +0 -28
- package/src/chains/themes/index.spec.js +0 -19
- package/src/chains/veiled-variants/index.examples.js +0 -18
- package/src/chains/veiled-variants/index.js +0 -107
- package/src/chains/veiled-variants/index.spec.js +0 -40
- package/src/constants/common.js +0 -7
- package/src/constants/messages.js +0 -3
- package/src/constants/models.js +0 -183
- package/src/index.js +0 -193
- package/src/json-schemas/README.md +0 -13
- package/src/json-schemas/cars-test.json +0 -11
- package/src/json-schemas/index.js +0 -12
- package/src/json-schemas/intent.json +0 -38
- package/src/json-schemas/schema-dot-org-photograph.json +0 -133
- package/src/json-schemas/schema-dot-org-place.json +0 -129
- package/src/lib/README.md +0 -26
- package/src/lib/any-signal/index.js +0 -28
- package/src/lib/bulk-filter/README.md +0 -22
- package/src/lib/bulk-filter/index.examples.js +0 -27
- package/src/lib/bulk-filter/index.js +0 -63
- package/src/lib/bulk-filter/index.spec.js +0 -38
- package/src/lib/bulk-find/README.md +0 -18
- package/src/lib/bulk-find/index.examples.js +0 -19
- package/src/lib/bulk-find/index.js +0 -30
- package/src/lib/bulk-find/index.spec.js +0 -41
- package/src/lib/chatgpt/index.js +0 -163
- package/src/lib/combinations/index.js +0 -30
- package/src/lib/combinations/index.spec.js +0 -23
- package/src/lib/editor/index.js +0 -31
- package/src/lib/functional/index.js +0 -28
- package/src/lib/logger-service/index.js +0 -32
- package/src/lib/parse-js-parts/index.js +0 -321
- package/src/lib/parse-js-parts/index.spec.js +0 -156
- package/src/lib/parse-llm-list/README.md +0 -39
- package/src/lib/parse-llm-list/index.js +0 -54
- package/src/lib/parse-llm-list/index.spec.js +0 -59
- package/src/lib/path-aliases/index.js +0 -37
- package/src/lib/path-aliases/index.spec.js +0 -64
- package/src/lib/pave/index.js +0 -34
- package/src/lib/pave/index.spec.js +0 -76
- package/src/lib/prompt-cache/index.js +0 -50
- package/src/lib/retry/index.js +0 -66
- package/src/lib/retry/index.spec.js +0 -86
- package/src/lib/ring-buffer/README.md +0 -460
- package/src/lib/ring-buffer/index.js +0 -1074
- package/src/lib/search-best-first/city-walk.spec.js +0 -37
- package/src/lib/search-best-first/index.js +0 -97
- package/src/lib/search-best-first/index.spec.js +0 -35
- package/src/lib/search-js-files/code-features-property-definitions.json +0 -123
- package/src/lib/search-js-files/index.examples.js +0 -22
- package/src/lib/search-js-files/index.js +0 -155
- package/src/lib/search-js-files/index.spec.js +0 -34
- package/src/lib/search-js-files/scan-file.js +0 -242
- package/src/lib/shorten-text/index.js +0 -25
- package/src/lib/shorten-text/index.spec.js +0 -68
- package/src/lib/strip-numeric/index.js +0 -5
- package/src/lib/strip-response/index.js +0 -30
- package/src/lib/template-replace/index.js +0 -23
- package/src/lib/template-replace/index.spec.js +0 -60
- package/src/lib/timed-abort-controller/index.js +0 -41
- package/src/lib/to-bool/index.js +0 -8
- package/src/lib/to-date/index.js +0 -11
- package/src/lib/to-enum/index.js +0 -14
- package/src/lib/to-number/index.js +0 -12
- package/src/lib/to-number-with-units/index.js +0 -51
- package/src/lib/transcribe/index.js +0 -78
- package/src/prompts/README.md +0 -17
- package/src/prompts/as-enum.js +0 -5
- package/src/prompts/as-json-schema.js +0 -9
- package/src/prompts/as-object-with-schema.js +0 -26
- package/src/prompts/as-schema-org-text.js +0 -25
- package/src/prompts/as-schema-org-type.js +0 -1
- package/src/prompts/blog-post.js +0 -7
- package/src/prompts/code-features.js +0 -24
- package/src/prompts/constants.js +0 -101
- package/src/prompts/features-json-schema.js +0 -27
- package/src/prompts/generate-collection.js +0 -26
- package/src/prompts/generate-list.js +0 -48
- package/src/prompts/generate-questions.js +0 -19
- package/src/prompts/index.js +0 -20
- package/src/prompts/intent.js +0 -60
- package/src/prompts/output-succinct-names.js +0 -3
- package/src/prompts/select-from-threshold.js +0 -17
- package/src/prompts/sort.js +0 -31
- package/src/prompts/style.js +0 -38
- package/src/prompts/summarize.js +0 -13
- package/src/prompts/token-budget.js +0 -3
- package/src/prompts/wrap-list.js +0 -11
- package/src/prompts/wrap-variable.js +0 -36
- package/src/services/llm-model/global-overrides.spec.js +0 -432
- package/src/services/llm-model/index.js +0 -308
- package/src/services/llm-model/model.js +0 -21
- package/src/services/llm-model/negotiate.spec.js +0 -447
- package/src/services/redis/index.js +0 -147
- package/src/test/setup.js +0 -20
- package/src/verblets/README.md +0 -26
- package/src/verblets/auto/index.examples.js +0 -31
- package/src/verblets/auto/index.js +0 -28
- package/src/verblets/auto/index.spec.js +0 -32
- package/src/verblets/bool/README.md +0 -36
- package/src/verblets/bool/index.examples.js +0 -80
- package/src/verblets/bool/index.js +0 -25
- package/src/verblets/bool/index.schema.json +0 -14
- package/src/verblets/bool/index.spec.js +0 -33
- package/src/verblets/central-tendency/README.md +0 -166
- package/src/verblets/central-tendency/central-tendency-result.json +0 -24
- package/src/verblets/central-tendency/index.examples.js +0 -196
- package/src/verblets/central-tendency/index.js +0 -171
- package/src/verblets/central-tendency/index.spec.js +0 -148
- package/src/verblets/enum/index.examples.js +0 -30
- package/src/verblets/enum/index.js +0 -18
- package/src/verblets/enum/index.spec.js +0 -35
- package/src/verblets/expect/README.md +0 -64
- package/src/verblets/expect/index.examples.js +0 -109
- package/src/verblets/expect/index.js +0 -75
- package/src/verblets/expect/index.spec.js +0 -127
- package/src/verblets/intent/index.examples.js +0 -139
- package/src/verblets/intent/index.js +0 -60
- package/src/verblets/intent/index.spec.js +0 -31
- package/src/verblets/intersection/README.md +0 -16
- package/src/verblets/intersection/index.examples.js +0 -89
- package/src/verblets/intersection/index.js +0 -84
- package/src/verblets/intersection/index.spec.js +0 -60
- package/src/verblets/intersection/intersection-result.json +0 -16
- package/src/verblets/list-expand/README.md +0 -10
- package/src/verblets/list-expand/index.examples.js +0 -14
- package/src/verblets/list-expand/index.js +0 -104
- package/src/verblets/list-expand/index.spec.js +0 -18
- package/src/verblets/list-expand/list-expand-result.json +0 -16
- package/src/verblets/list-filter/README.md +0 -22
- package/src/verblets/list-filter/index.examples.js +0 -26
- package/src/verblets/list-filter/index.js +0 -18
- package/src/verblets/list-filter/index.spec.js +0 -19
- package/src/verblets/list-find/README.md +0 -11
- package/src/verblets/list-find/index.examples.js +0 -15
- package/src/verblets/list-find/index.js +0 -17
- package/src/verblets/list-find/index.spec.js +0 -19
- package/src/verblets/list-group/README.md +0 -16
- package/src/verblets/list-group/index.examples.js +0 -16
- package/src/verblets/list-group/index.js +0 -112
- package/src/verblets/list-group/index.spec.js +0 -35
- package/src/verblets/list-group/list-group-result.json +0 -16
- package/src/verblets/list-map/README.md +0 -11
- package/src/verblets/list-map/index.examples.js +0 -15
- package/src/verblets/list-map/index.js +0 -26
- package/src/verblets/list-map/index.spec.js +0 -17
- package/src/verblets/list-reduce/README.md +0 -10
- package/src/verblets/list-reduce/index.examples.js +0 -14
- package/src/verblets/list-reduce/index.js +0 -21
- package/src/verblets/list-reduce/index.spec.js +0 -27
- package/src/verblets/list-reduce/index.spec.jsx +0 -27
- package/src/verblets/name/README.md +0 -15
- package/src/verblets/name/index.examples.js +0 -28
- package/src/verblets/name/index.js +0 -19
- package/src/verblets/name/index.spec.js +0 -33
- package/src/verblets/name-similar-to/README.md +0 -26
- package/src/verblets/name-similar-to/index.examples.js +0 -18
- package/src/verblets/name-similar-to/index.js +0 -20
- package/src/verblets/name-similar-to/index.spec.js +0 -13
- package/src/verblets/number/index.examples.js +0 -199
- package/src/verblets/number/index.js +0 -25
- package/src/verblets/number/index.spec.js +0 -33
- package/src/verblets/number-with-units/index.examples.js +0 -38
- package/src/verblets/number-with-units/index.js +0 -84
- package/src/verblets/number-with-units/index.spec.js +0 -46
- package/src/verblets/number-with-units/number-with-units-result.json +0 -23
- package/src/verblets/schema-org/index.examples.js +0 -51
- package/src/verblets/schema-org/index.js +0 -37
- package/src/verblets/schema-org/index.spec.js +0 -39
- package/src/verblets/sentiment/README.md +0 -10
- package/src/verblets/sentiment/index.examples.js +0 -20
- package/src/verblets/sentiment/index.js +0 -9
- package/src/verblets/sentiment/index.spec.js +0 -20
- package/src/verblets/to-object/README.md +0 -38
- package/src/verblets/to-object/index.examples.js +0 -29
- package/src/verblets/to-object/index.js +0 -131
- package/src/verblets/to-object/index.spec.js +0 -71
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
-
"type": "object",
|
|
4
|
-
"additionalProperties": false,
|
|
5
|
-
"properties": {
|
|
6
|
-
"@context": {
|
|
7
|
-
"type": "string",
|
|
8
|
-
"pattern": "^https://schema.org$"
|
|
9
|
-
},
|
|
10
|
-
"@type": {
|
|
11
|
-
"type": "string",
|
|
12
|
-
"enum": ["Place", "City"]
|
|
13
|
-
},
|
|
14
|
-
"name": {
|
|
15
|
-
"type": "string"
|
|
16
|
-
},
|
|
17
|
-
"alternateName": {
|
|
18
|
-
"type": "string"
|
|
19
|
-
},
|
|
20
|
-
"description": {
|
|
21
|
-
"type": "string"
|
|
22
|
-
},
|
|
23
|
-
"population": {
|
|
24
|
-
"type": "integer",
|
|
25
|
-
"minimum": 0
|
|
26
|
-
},
|
|
27
|
-
"area": {
|
|
28
|
-
"type": "object",
|
|
29
|
-
"additionalProperties": false,
|
|
30
|
-
"properties": {
|
|
31
|
-
"@type": {
|
|
32
|
-
"type": "string",
|
|
33
|
-
"enum": ["QuantitativeValue"]
|
|
34
|
-
},
|
|
35
|
-
"value": {
|
|
36
|
-
"type": "number",
|
|
37
|
-
"minimum": 0
|
|
38
|
-
},
|
|
39
|
-
"unitCode": {
|
|
40
|
-
"type": "string"
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
},
|
|
44
|
-
"elevation": {
|
|
45
|
-
"type": "object",
|
|
46
|
-
"additionalProperties": false,
|
|
47
|
-
"properties": {
|
|
48
|
-
"@type": {
|
|
49
|
-
"type": "string",
|
|
50
|
-
"enum": ["QuantitativeValue"]
|
|
51
|
-
},
|
|
52
|
-
"value": {
|
|
53
|
-
"type": "number"
|
|
54
|
-
},
|
|
55
|
-
"unitCode": {
|
|
56
|
-
"type": "string"
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
},
|
|
60
|
-
"address": {
|
|
61
|
-
"type": "object",
|
|
62
|
-
"additionalProperties": false,
|
|
63
|
-
"properties": {
|
|
64
|
-
"@type": {
|
|
65
|
-
"type": "string",
|
|
66
|
-
"enum": ["PostalAddress"]
|
|
67
|
-
},
|
|
68
|
-
"streetAddress": {
|
|
69
|
-
"type": "string"
|
|
70
|
-
},
|
|
71
|
-
"addressLocality": {
|
|
72
|
-
"type": "string"
|
|
73
|
-
},
|
|
74
|
-
"addressRegion": {
|
|
75
|
-
"type": "string"
|
|
76
|
-
},
|
|
77
|
-
"postalCode": {
|
|
78
|
-
"type": "string"
|
|
79
|
-
},
|
|
80
|
-
"addressCountry": {
|
|
81
|
-
"type": "string"
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
},
|
|
85
|
-
"geo": {
|
|
86
|
-
"type": "object",
|
|
87
|
-
"additionalProperties": false,
|
|
88
|
-
"properties": {
|
|
89
|
-
"@type": {
|
|
90
|
-
"type": "string",
|
|
91
|
-
"enum": ["GeoCoordinates"]
|
|
92
|
-
},
|
|
93
|
-
"latitude": {
|
|
94
|
-
"type": "number"
|
|
95
|
-
},
|
|
96
|
-
"longitude": {
|
|
97
|
-
"type": "number"
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
},
|
|
101
|
-
"areaServed": {
|
|
102
|
-
"oneOf": [
|
|
103
|
-
{
|
|
104
|
-
"type": "string"
|
|
105
|
-
},
|
|
106
|
-
{
|
|
107
|
-
"type": "object",
|
|
108
|
-
"additionalProperties": false,
|
|
109
|
-
"properties": {
|
|
110
|
-
"@type": {
|
|
111
|
-
"type": "string",
|
|
112
|
-
"enum": ["AdministrativeArea"]
|
|
113
|
-
},
|
|
114
|
-
"name": {
|
|
115
|
-
"type": "string"
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
]
|
|
120
|
-
},
|
|
121
|
-
"additionalType": {
|
|
122
|
-
"type": "string"
|
|
123
|
-
},
|
|
124
|
-
"sameAs": {
|
|
125
|
-
"type": "string"
|
|
126
|
-
}
|
|
127
|
-
},
|
|
128
|
-
"required": ["@type", "name"]
|
|
129
|
-
}
|
package/src/lib/README.md
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
# Library Helpers
|
|
2
|
-
|
|
3
|
-
The `lib` directory houses reusable utilities used by verblets and chains. Each subfolder contains a focused helper function or class.
|
|
4
|
-
|
|
5
|
-
Modules include:
|
|
6
|
-
|
|
7
|
-
<!-- commonly used utilities -->
|
|
8
|
-
- [chatgpt](./chatgpt) – wrapper around OpenAI's ChatGPT API.
|
|
9
|
-
- [prompt-cache](./prompt-cache) – cache prompts/responses locally.
|
|
10
|
-
- [retry](./retry) – generic async retry helper.
|
|
11
|
-
- [search-best-first](./search-best-first) – best-first tree search algorithm.
|
|
12
|
-
- [search-js-files](./search-js-files) – locate and analyze JavaScript files.
|
|
13
|
-
- [combinations](./combinations) – generate array combinations.
|
|
14
|
-
- [rangeCombinations](./combinations) – combinations across multiple sizes.
|
|
15
|
-
- [shorten-text](./shorten-text) – shorten text using an LLM.
|
|
16
|
-
- [bulk-map](./bulk-map) – map lists in retryable batches.
|
|
17
|
-
- [bulk-filter](./bulk-filter) – filter lists in retryable batches.
|
|
18
|
-
- [strip-numeric](./strip-numeric) – remove non-digit characters.
|
|
19
|
-
- [strip-response](./strip-response) – clean up model responses.
|
|
20
|
-
- [to-bool](./to-bool) – parse text into a boolean.
|
|
21
|
-
- [to-enum](./to-enum) – parse text into an enum value.
|
|
22
|
-
- [to-number](./to-number) – parse text into a number.
|
|
23
|
-
- [to-number-with-units](./to-number-with-units) – parse numbers that include units.
|
|
24
|
-
- [transcribe](./transcribe) – microphone transcription via Whisper.
|
|
25
|
-
|
|
26
|
-
These helpers are building blocks used throughout the rest of the project.
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Creates a new AbortSignal that is triggered when any of the given signals are aborted.
|
|
3
|
-
*
|
|
4
|
-
* @param {AbortSignal[]} signals - An array of AbortSignal instances to listen to.
|
|
5
|
-
* @returns {AbortSignal} - A new AbortSignal that is aborted when any of the input signals are aborted.
|
|
6
|
-
*
|
|
7
|
-
* @example
|
|
8
|
-
* const abortController1 = new AbortController();
|
|
9
|
-
* const abortController2 = new AbortController();
|
|
10
|
-
* const combinedSignal = anySignal([abortController1.signal, abortController2.signal]);
|
|
11
|
-
* fetch('https://example.com', { signal: combinedSignal });
|
|
12
|
-
* abortController1.abort(); // This will abort the fetch operation
|
|
13
|
-
*/
|
|
14
|
-
export default (signalsInitial) => {
|
|
15
|
-
const signals = signalsInitial.filter((s) => s);
|
|
16
|
-
|
|
17
|
-
const controller = new AbortController();
|
|
18
|
-
for (const signal of signals) {
|
|
19
|
-
if (signal.aborted) {
|
|
20
|
-
controller.abort();
|
|
21
|
-
break;
|
|
22
|
-
}
|
|
23
|
-
signal.addEventListener('abort', () => {
|
|
24
|
-
controller.abort();
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
return controller.signal;
|
|
28
|
-
};
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
# bulk-filter
|
|
2
|
-
|
|
3
|
-
Filter long lists in batches using `listFilter`. Batches that fail can be retried.
|
|
4
|
-
|
|
5
|
-
```javascript
|
|
6
|
-
import bulkFilter from './index.js';
|
|
7
|
-
|
|
8
|
-
const reflections = [
|
|
9
|
-
'Losing that match taught me the value of persistence.',
|
|
10
|
-
"I hate losing and it proves I'm worthless.",
|
|
11
|
-
'After failing my exam, I studied harder and passed the retake.',
|
|
12
|
-
"No matter what I do, I'll never succeed.",
|
|
13
|
-
];
|
|
14
|
-
const growth = await bulkFilter(
|
|
15
|
-
reflections,
|
|
16
|
-
'keep only reflections that show personal growth or learning from mistakes'
|
|
17
|
-
);
|
|
18
|
-
// growth === [
|
|
19
|
-
// 'Losing that match taught me the value of persistence.',
|
|
20
|
-
// 'After failing my exam, I studied harder and passed the retake.',
|
|
21
|
-
// ]
|
|
22
|
-
```
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import bulkFilter from './index.js';
|
|
3
|
-
import { longTestTimeout } from '../../constants/common.js';
|
|
4
|
-
|
|
5
|
-
describe('bulk-filter examples', () => {
|
|
6
|
-
it(
|
|
7
|
-
'filters items in batches',
|
|
8
|
-
async () => {
|
|
9
|
-
const entries = [
|
|
10
|
-
'Losing that match taught me the value of persistence.',
|
|
11
|
-
"I hate losing and it proves I'm worthless.",
|
|
12
|
-
'After failing my exam, I studied harder and passed the retake.',
|
|
13
|
-
"No matter what I do, I'll never succeed.",
|
|
14
|
-
];
|
|
15
|
-
const result = await bulkFilter(
|
|
16
|
-
entries,
|
|
17
|
-
'keep only reflections that show personal growth or learning from mistakes',
|
|
18
|
-
2
|
|
19
|
-
);
|
|
20
|
-
expect(result).toStrictEqual([
|
|
21
|
-
'Losing that match taught me the value of persistence.',
|
|
22
|
-
'After failing my exam, I studied harder and passed the retake.',
|
|
23
|
-
]);
|
|
24
|
-
},
|
|
25
|
-
longTestTimeout
|
|
26
|
-
);
|
|
27
|
-
});
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import listFilter from '../../verblets/list-filter/index.js';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Filter a list by processing newline-delimited batches with `listFilter`.
|
|
5
|
-
*
|
|
6
|
-
* @param {string[]} list - array of items to evaluate
|
|
7
|
-
* @param {string} instructions - filter instructions for `listFilter`
|
|
8
|
-
* @param {number} [chunkSize=10] - how many items per batch
|
|
9
|
-
* @returns {Promise<string[]>} filtered items preserving order
|
|
10
|
-
*/
|
|
11
|
-
export default async function bulkFilter(list, instructions, chunkSize = 10) {
|
|
12
|
-
const batches = [];
|
|
13
|
-
for (let i = 0; i < list.length; i += chunkSize) {
|
|
14
|
-
const batch = list.slice(i, i + chunkSize);
|
|
15
|
-
const filtered = await listFilter(batch, instructions);
|
|
16
|
-
batches.push(filtered);
|
|
17
|
-
}
|
|
18
|
-
return batches.flat();
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Retry filtering failed batches until `maxAttempts` is reached.
|
|
23
|
-
*
|
|
24
|
-
* @param {string[]} list
|
|
25
|
-
* @param {string} instructions
|
|
26
|
-
* @param {object} [options]
|
|
27
|
-
* @param {number} [options.chunkSize=10]
|
|
28
|
-
* @param {number} [options.maxAttempts=3]
|
|
29
|
-
* @returns {Promise<string[]>}
|
|
30
|
-
*/
|
|
31
|
-
export async function bulkFilterRetry(
|
|
32
|
-
list,
|
|
33
|
-
instructions,
|
|
34
|
-
{ chunkSize = 10, maxAttempts = 3 } = {}
|
|
35
|
-
) {
|
|
36
|
-
const batches = [];
|
|
37
|
-
for (let i = 0; i < list.length; i += chunkSize) {
|
|
38
|
-
batches.push(list.slice(i, i + chunkSize));
|
|
39
|
-
}
|
|
40
|
-
const results = new Array(batches.length).fill(null);
|
|
41
|
-
let pending = batches.map((_, idx) => idx);
|
|
42
|
-
|
|
43
|
-
for (let attempt = 0; attempt < maxAttempts && pending.length > 0; attempt += 1) {
|
|
44
|
-
const newPending = [];
|
|
45
|
-
for (const idx of pending) {
|
|
46
|
-
const batch = batches[idx];
|
|
47
|
-
try {
|
|
48
|
-
const filtered = await listFilter(batch, instructions);
|
|
49
|
-
const valid = filtered.every((line) => batch.includes(line));
|
|
50
|
-
if (valid) {
|
|
51
|
-
results[idx] = filtered;
|
|
52
|
-
} else {
|
|
53
|
-
newPending.push(idx);
|
|
54
|
-
}
|
|
55
|
-
} catch {
|
|
56
|
-
newPending.push(idx);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
pending = newPending;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
return results.flat().filter(Boolean);
|
|
63
|
-
}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it, vi, beforeEach } from 'vitest';
|
|
2
|
-
import bulkFilter, { bulkFilterRetry } from './index.js';
|
|
3
|
-
import listFilter from '../../verblets/list-filter/index.js';
|
|
4
|
-
|
|
5
|
-
vi.mock('../../verblets/list-filter/index.js', () => ({
|
|
6
|
-
default: vi.fn(async (items, instructions) => {
|
|
7
|
-
if (items.includes('FAIL')) throw new Error('fail');
|
|
8
|
-
return items.filter((l) => l.includes(instructions));
|
|
9
|
-
}),
|
|
10
|
-
}));
|
|
11
|
-
|
|
12
|
-
beforeEach(() => {
|
|
13
|
-
vi.clearAllMocks();
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
describe('bulk-filter', () => {
|
|
17
|
-
it('filters fragments in batches', async () => {
|
|
18
|
-
const result = await bulkFilter(['aa', 'b', 'ca', 'd'], 'a', 2);
|
|
19
|
-
expect(result).toStrictEqual(['aa', 'ca']);
|
|
20
|
-
expect(listFilter).toHaveBeenCalledTimes(2);
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
it('retries failed batches', async () => {
|
|
24
|
-
let call = 0;
|
|
25
|
-
listFilter.mockImplementation(async (items) => {
|
|
26
|
-
call += 1;
|
|
27
|
-
if (call === 1) throw new Error('fail');
|
|
28
|
-
return items.filter((l) => l.includes('a'));
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
const result = await bulkFilterRetry(['aa', 'b', 'ca'], 'a', {
|
|
32
|
-
chunkSize: 2,
|
|
33
|
-
maxAttempts: 2,
|
|
34
|
-
});
|
|
35
|
-
expect(result).toStrictEqual(['aa', 'ca']);
|
|
36
|
-
expect(listFilter).toHaveBeenCalledTimes(3);
|
|
37
|
-
});
|
|
38
|
-
});
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
# bulk-find
|
|
2
|
-
|
|
3
|
-
Search large lists in batches using `listFind` and return the first matching item.
|
|
4
|
-
Failed batches can be retried with `bulkFindRetry`.
|
|
5
|
-
|
|
6
|
-
```javascript
|
|
7
|
-
import bulkFind, { bulkFindRetry } from './index.js';
|
|
8
|
-
|
|
9
|
-
const diaryEntries = [
|
|
10
|
-
'Hiked up the mountains today and saw breathtaking views',
|
|
11
|
-
'Visited the local market and tried a spicy stew',
|
|
12
|
-
'Spotted penguins playing on the beach this morning'
|
|
13
|
-
];
|
|
14
|
-
const penguinMoment = await bulkFindRetry(diaryEntries, 'mentions penguins', {
|
|
15
|
-
chunkSize: 2
|
|
16
|
-
});
|
|
17
|
-
// penguinMoment === 'Spotted penguins playing on the beach this morning'
|
|
18
|
-
```
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { bulkFindRetry } from './index.js';
|
|
3
|
-
import { longTestTimeout } from '../../constants/common.js';
|
|
4
|
-
|
|
5
|
-
describe('bulk-find examples', () => {
|
|
6
|
-
it(
|
|
7
|
-
'finds an item across batches',
|
|
8
|
-
async () => {
|
|
9
|
-
const diaryEntries = [
|
|
10
|
-
'Hiked up the mountains today and saw breathtaking views',
|
|
11
|
-
'Visited the local market and tried a spicy stew',
|
|
12
|
-
'Spotted penguins playing on the beach this morning',
|
|
13
|
-
];
|
|
14
|
-
const result = await bulkFindRetry(diaryEntries, 'mentions penguins');
|
|
15
|
-
expect(result).toBeDefined();
|
|
16
|
-
},
|
|
17
|
-
longTestTimeout
|
|
18
|
-
);
|
|
19
|
-
});
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import listFind from '../../verblets/list-find/index.js';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Search a list in batches using `listFind`.
|
|
5
|
-
*
|
|
6
|
-
* @param { string[] } list - array of items to search
|
|
7
|
-
* @param { string } instructions - criteria passed to `listFind`
|
|
8
|
-
* @param { number } [chunkSize=10] - how many items per batch
|
|
9
|
-
* @returns { Promise<string|undefined> } first match or undefined
|
|
10
|
-
*/
|
|
11
|
-
export default async function bulkFind(list, instructions, chunkSize = 10) {
|
|
12
|
-
for (let i = 0; i < list.length; i += chunkSize) {
|
|
13
|
-
const batch = list.slice(i, i + chunkSize);
|
|
14
|
-
try {
|
|
15
|
-
const result = await listFind(batch, instructions);
|
|
16
|
-
if (result) return result;
|
|
17
|
-
} catch {
|
|
18
|
-
// ignore and continue to next batch
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
return undefined;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export async function bulkFindRetry(list, instructions, { chunkSize = 10, maxAttempts = 3 } = {}) {
|
|
25
|
-
for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
|
|
26
|
-
const result = await bulkFind(list, instructions, chunkSize);
|
|
27
|
-
if (result) return result;
|
|
28
|
-
}
|
|
29
|
-
return undefined;
|
|
30
|
-
}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it, vi, beforeEach } from 'vitest';
|
|
2
|
-
import bulkFind, { bulkFindRetry } from './index.js';
|
|
3
|
-
import listFind from '../../verblets/list-find/index.js';
|
|
4
|
-
|
|
5
|
-
vi.mock('../../verblets/list-find/index.js', () => ({
|
|
6
|
-
default: vi.fn(async (list, instructions) => list.find((l) => l.includes(instructions)) || ''),
|
|
7
|
-
}));
|
|
8
|
-
|
|
9
|
-
beforeEach(() => {
|
|
10
|
-
vi.clearAllMocks();
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
describe('bulk-find', () => {
|
|
14
|
-
it('returns first match across batches', async () => {
|
|
15
|
-
const result = await bulkFind(['a', 'b', 'c', 'd'], 'c', 2);
|
|
16
|
-
expect(result).toBe('c');
|
|
17
|
-
expect(listFind).toHaveBeenCalledTimes(2);
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
it('returns undefined when not found', async () => {
|
|
21
|
-
listFind.mockResolvedValueOnce('');
|
|
22
|
-
listFind.mockResolvedValueOnce('');
|
|
23
|
-
const result = await bulkFind(['a', 'b'], 'x', 1);
|
|
24
|
-
expect(result).toBeUndefined();
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
it('retries until a match is found', async () => {
|
|
28
|
-
listFind.mockResolvedValueOnce('');
|
|
29
|
-
listFind.mockResolvedValueOnce('c');
|
|
30
|
-
const result = await bulkFindRetry(['a', 'b', 'c'], 'c', { chunkSize: 2, maxAttempts: 2 });
|
|
31
|
-
expect(result).toBe('c');
|
|
32
|
-
expect(listFind).toHaveBeenCalledTimes(2);
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
it('returns undefined after maxAttempts', async () => {
|
|
36
|
-
listFind.mockResolvedValue('');
|
|
37
|
-
const result = await bulkFindRetry(['a', 'b'], 'x', { chunkSize: 1, maxAttempts: 2 });
|
|
38
|
-
expect(result).toBeUndefined();
|
|
39
|
-
expect(listFind).toHaveBeenCalledTimes(4);
|
|
40
|
-
});
|
|
41
|
-
});
|
package/src/lib/chatgpt/index.js
DELETED
|
@@ -1,163 +0,0 @@
|
|
|
1
|
-
import fetch from 'node-fetch';
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
debugPromptGlobally,
|
|
5
|
-
debugPromptGloballyIfChanged,
|
|
6
|
-
debugResultGlobally,
|
|
7
|
-
debugResultGloballyIfChanged,
|
|
8
|
-
models,
|
|
9
|
-
} from '../../constants/models.js';
|
|
10
|
-
import anySignal from '../any-signal/index.js';
|
|
11
|
-
import { get as getPromptResult, set as setPromptResult } from '../prompt-cache/index.js';
|
|
12
|
-
import TimedAbortController from '../timed-abort-controller/index.js';
|
|
13
|
-
import modelService from '../../services/llm-model/index.js';
|
|
14
|
-
import { getClient as getRedis } from '../../services/redis/index.js';
|
|
15
|
-
|
|
16
|
-
const shapeOutputDefault = (result) => {
|
|
17
|
-
// GPT-4
|
|
18
|
-
if (result.choices[0].message.tool_calls?.length) {
|
|
19
|
-
const toolCall = result.choices[0].message.tool_calls[0];
|
|
20
|
-
return {
|
|
21
|
-
name: toolCall.function.name,
|
|
22
|
-
arguments: JSON.parse(toolCall.function.arguments),
|
|
23
|
-
result: result.choices[0].message.tool_calls[0].function,
|
|
24
|
-
};
|
|
25
|
-
}
|
|
26
|
-
if (result.choices[0].message) {
|
|
27
|
-
return result.choices[0].message.content.trim();
|
|
28
|
-
}
|
|
29
|
-
return result.choices[0].text.trim();
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
const onBeforeRequestDefault = ({ debugPrompt, isCached, prompt }) => {
|
|
33
|
-
if (debugPrompt || debugPromptGlobally || (debugPromptGloballyIfChanged && !isCached)) {
|
|
34
|
-
console.error('+++ DEBUG PROMPT +++');
|
|
35
|
-
console.error(prompt);
|
|
36
|
-
console.error('+++ DEBUG PROMPT END +++');
|
|
37
|
-
}
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
const onAfterRequestDefault = ({ debugResult, isCached, resultShaped }) => {
|
|
41
|
-
if (debugResult || debugResultGlobally || (debugResultGloballyIfChanged && !isCached)) {
|
|
42
|
-
console.error('+++ DEBUG RESULT +++');
|
|
43
|
-
console.error(resultShaped);
|
|
44
|
-
console.error('+++ DEBUG RESULT END +++');
|
|
45
|
-
}
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
export const run = async (prompt, config = {}) => {
|
|
49
|
-
// Handle config parameter - can be string (model name) or object (full options)
|
|
50
|
-
let options;
|
|
51
|
-
if (typeof config === 'string') {
|
|
52
|
-
options = { modelOptions: { modelName: config } };
|
|
53
|
-
} else {
|
|
54
|
-
options = config;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
const {
|
|
58
|
-
abortSignal,
|
|
59
|
-
debugPrompt,
|
|
60
|
-
debugResult,
|
|
61
|
-
forceQuery,
|
|
62
|
-
modelOptions = {},
|
|
63
|
-
onAfterRequest = onAfterRequestDefault,
|
|
64
|
-
onBeforeRequest = onBeforeRequestDefault,
|
|
65
|
-
shapeOutput = shapeOutputDefault,
|
|
66
|
-
} = options;
|
|
67
|
-
|
|
68
|
-
// Apply global overrides to model options
|
|
69
|
-
const modelOptionsWithOverrides = modelService.applyGlobalOverrides(modelOptions);
|
|
70
|
-
|
|
71
|
-
// Check if negotiation was applied via global override
|
|
72
|
-
const negotiationFromGlobalOverride = modelService.getGlobalOverride('negotiate');
|
|
73
|
-
|
|
74
|
-
const modelNameNegotiated = modelOptionsWithOverrides.negotiate
|
|
75
|
-
? modelService.negotiateModel(
|
|
76
|
-
// If negotiation came from global override, don't use preferred model
|
|
77
|
-
negotiationFromGlobalOverride ? null : modelOptionsWithOverrides.modelName,
|
|
78
|
-
modelOptionsWithOverrides.negotiate
|
|
79
|
-
)
|
|
80
|
-
: modelOptionsWithOverrides.modelName;
|
|
81
|
-
|
|
82
|
-
const modelFound = modelService.getModel(modelNameNegotiated);
|
|
83
|
-
|
|
84
|
-
// Use model-specific API URL and key if defined, otherwise fall back to defaults
|
|
85
|
-
const apiUrl = modelFound?.apiUrl || models.fastGood.apiUrl;
|
|
86
|
-
const apiKey = modelFound?.apiKey || models.fastGood.apiKey;
|
|
87
|
-
|
|
88
|
-
const requestConfig = modelService.getRequestConfig({
|
|
89
|
-
prompt,
|
|
90
|
-
...modelOptionsWithOverrides,
|
|
91
|
-
modelName: modelNameNegotiated,
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
// Check if caching is disabled via environment variable
|
|
95
|
-
const cachingDisabled = process.env.DISABLE_CACHE === 'true';
|
|
96
|
-
|
|
97
|
-
let cacheResult = null;
|
|
98
|
-
let cache = null;
|
|
99
|
-
|
|
100
|
-
if (!cachingDisabled) {
|
|
101
|
-
cache = await getRedis();
|
|
102
|
-
const { result } = await getPromptResult(cache, requestConfig);
|
|
103
|
-
cacheResult = result;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
onBeforeRequest({
|
|
107
|
-
isCached: !!cacheResult,
|
|
108
|
-
debugPrompt,
|
|
109
|
-
prompt,
|
|
110
|
-
requestConfig,
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
let result = cacheResult;
|
|
114
|
-
if (!cacheResult || forceQuery) {
|
|
115
|
-
// Use custom requestTimeout from modelOptions if provided, otherwise use model default
|
|
116
|
-
const requestTimeout =
|
|
117
|
-
modelOptionsWithOverrides.requestTimeout ||
|
|
118
|
-
modelService.getModel(modelNameNegotiated).requestTimeout;
|
|
119
|
-
|
|
120
|
-
const timeoutController = new TimedAbortController(requestTimeout);
|
|
121
|
-
|
|
122
|
-
// console.log(requestConfig, `${apiUrl}${modelFound.endpoint}`)
|
|
123
|
-
|
|
124
|
-
const response = await fetch(`${apiUrl}${modelFound.endpoint}`, {
|
|
125
|
-
method: 'POST',
|
|
126
|
-
headers: {
|
|
127
|
-
Authorization: `Bearer ${apiKey}`,
|
|
128
|
-
'Content-Type': 'application/json',
|
|
129
|
-
},
|
|
130
|
-
body: JSON.stringify(requestConfig),
|
|
131
|
-
signal: anySignal([abortSignal, timeoutController.signal]),
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
result = await response.json();
|
|
135
|
-
|
|
136
|
-
if (!response.ok) {
|
|
137
|
-
const vars = [`status: ${response?.status}`, `type: ${result?.error?.type}`].join(', ');
|
|
138
|
-
throw new Error(`Completions request [error]: ${result?.error?.message} (${vars})`);
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
timeoutController.clearTimeout();
|
|
142
|
-
|
|
143
|
-
// Only cache the result if caching is not disabled
|
|
144
|
-
if (!cachingDisabled && cache) {
|
|
145
|
-
await setPromptResult(cache, requestConfig, result);
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
const resultShaped = shapeOutput(result);
|
|
150
|
-
|
|
151
|
-
onAfterRequest({
|
|
152
|
-
debugResult,
|
|
153
|
-
isCached: !!cacheResult,
|
|
154
|
-
prompt,
|
|
155
|
-
requestConfig,
|
|
156
|
-
result,
|
|
157
|
-
resultShaped,
|
|
158
|
-
});
|
|
159
|
-
|
|
160
|
-
return resultShaped;
|
|
161
|
-
};
|
|
162
|
-
|
|
163
|
-
export default run;
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
export default function combinations(items, size = 2) {
|
|
2
|
-
const result = [];
|
|
3
|
-
if (!Array.isArray(items) || size < 1) return result;
|
|
4
|
-
|
|
5
|
-
const combo = [];
|
|
6
|
-
const generate = (start) => {
|
|
7
|
-
if (combo.length === size) {
|
|
8
|
-
result.push([...combo]);
|
|
9
|
-
return;
|
|
10
|
-
}
|
|
11
|
-
for (let i = start; i < items.length; i++) {
|
|
12
|
-
combo.push(items[i]);
|
|
13
|
-
generate(i + 1);
|
|
14
|
-
combo.pop();
|
|
15
|
-
}
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
generate(0);
|
|
19
|
-
return result;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export function rangeCombinations(items, minSize = 2, maxSize = items.length) {
|
|
23
|
-
const sets = [];
|
|
24
|
-
if (!Array.isArray(items)) return sets;
|
|
25
|
-
const upper = Math.min(items.length, maxSize);
|
|
26
|
-
for (let s = minSize; s <= upper; s++) {
|
|
27
|
-
sets.push(...combinations(items, s));
|
|
28
|
-
}
|
|
29
|
-
return sets;
|
|
30
|
-
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import combinations, { rangeCombinations } from './index.js';
|
|
3
|
-
|
|
4
|
-
describe('combinations helper', () => {
|
|
5
|
-
it('generates pairwise combinations', () => {
|
|
6
|
-
const result = combinations(['a', 'b', 'c'], 2);
|
|
7
|
-
expect(result).toStrictEqual([
|
|
8
|
-
['a', 'b'],
|
|
9
|
-
['a', 'c'],
|
|
10
|
-
['b', 'c'],
|
|
11
|
-
]);
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
it('generates combinations of varying sizes', () => {
|
|
15
|
-
const result = rangeCombinations(['a', 'b', 'c']);
|
|
16
|
-
expect(result).toStrictEqual([
|
|
17
|
-
['a', 'b'],
|
|
18
|
-
['a', 'c'],
|
|
19
|
-
['b', 'c'],
|
|
20
|
-
['a', 'b', 'c'],
|
|
21
|
-
]);
|
|
22
|
-
});
|
|
23
|
-
});
|