@far-world-labs/verblets 0.2.0 → 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 -11
- 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 -12
- 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/clear-redis.js +0 -74
- 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/conversation/README.md +0 -26
- package/src/chains/conversation/index.examples.js +0 -398
- package/src/chains/conversation/index.js +0 -126
- package/src/chains/conversation/index.spec.js +0 -148
- package/src/chains/conversation/turn-policies.js +0 -93
- package/src/chains/conversation/turn-policies.md +0 -123
- package/src/chains/conversation/turn-policies.spec.js +0 -135
- 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 -207
- 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 -166
- package/src/chains/intersections/index.examples.js +0 -280
- package/src/chains/intersections/index.js +0 -218
- 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 -366
- package/src/chains/llm-logger/index.js +0 -591
- package/src/chains/llm-logger/index.spec.js +0 -391
- package/src/chains/llm-logger/schema.json +0 -105
- 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 -64
- package/src/chains/set-interval/index.js +0 -152
- 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 -13
- package/src/constants/messages.js +0 -3
- package/src/constants/models.js +0 -184
- package/src/index.js +0 -203
- 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/assert/README.md +0 -84
- package/src/lib/assert/index.js +0 -50
- 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 -82
- package/src/lib/ring-buffer/index.js +0 -235
- package/src/lib/ring-buffer/index.spec.js +0 -388
- 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/conversation-turn/README.md +0 -33
- package/src/verblets/conversation-turn/index.examples.js +0 -218
- package/src/verblets/conversation-turn/index.js +0 -68
- package/src/verblets/conversation-turn/index.spec.js +0 -77
- package/src/verblets/conversation-turn-multi/README.md +0 -31
- package/src/verblets/conversation-turn-multi/index.examples.js +0 -160
- package/src/verblets/conversation-turn-multi/index.js +0 -104
- package/src/verblets/conversation-turn-multi/index.spec.js +0 -63
- 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 -125
- 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/people-list/README.md +0 -28
- package/src/verblets/people-list/index.examples.js +0 -184
- package/src/verblets/people-list/index.js +0 -44
- package/src/verblets/people-list/index.spec.js +0 -49
- 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,138 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest';
|
|
2
|
-
import { longTestTimeout } from '../../constants/common.js';
|
|
3
|
-
import { expect as aiExpect } from '../expect/index.js';
|
|
4
|
-
import bulkCentralTendency from './index.js';
|
|
5
|
-
|
|
6
|
-
describe('Bulk Central Tendency Chain', () => {
|
|
7
|
-
it(
|
|
8
|
-
'processes multiple fruit items with consistent results',
|
|
9
|
-
async () => {
|
|
10
|
-
const items = ['apple', 'orange', 'durian', 'jackfruit', 'banana'];
|
|
11
|
-
const seedItems = ['apple', 'orange', 'banana', 'grape', 'strawberry'];
|
|
12
|
-
|
|
13
|
-
const results = await bulkCentralTendency(items, seedItems, {
|
|
14
|
-
context: 'Common fruits found in grocery stores',
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
expect(results).toHaveLength(5);
|
|
18
|
-
expect(results.every((r) => r && typeof r.score === 'number')).toBe(true);
|
|
19
|
-
expect(results.every((r) => r && r.score >= 0 && r.score <= 1)).toBe(true);
|
|
20
|
-
expect(results.every((r) => r && typeof r.reason === 'string')).toBe(true);
|
|
21
|
-
expect(results.every((r) => r && typeof r.confidence === 'number')).toBe(true);
|
|
22
|
-
|
|
23
|
-
// Use expect-chain for loose verification
|
|
24
|
-
const [isValidCentralityScoring] = await aiExpect(
|
|
25
|
-
results,
|
|
26
|
-
undefined,
|
|
27
|
-
'Do these centrality scores make sense? Common fruits like apple, orange, banana should have higher scores than exotic fruits like durian and jackfruit.'
|
|
28
|
-
);
|
|
29
|
-
expect(isValidCentralityScoring).toBe(true);
|
|
30
|
-
},
|
|
31
|
-
longTestTimeout
|
|
32
|
-
);
|
|
33
|
-
|
|
34
|
-
it(
|
|
35
|
-
'handles tool centrality with core features',
|
|
36
|
-
async () => {
|
|
37
|
-
const items = ['hammer', 'screwdriver', 'wrench', 'pliers', 'chainsaw'];
|
|
38
|
-
const seedItems = ['hammer', 'screwdriver', 'wrench', 'saw', 'drill'];
|
|
39
|
-
|
|
40
|
-
const results = await bulkCentralTendency(items, seedItems, {
|
|
41
|
-
context: 'Hand tools for construction and repair',
|
|
42
|
-
coreFeatures: ['handheld', 'mechanical', 'durable'],
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
expect(results).toHaveLength(5);
|
|
46
|
-
expect(results.every((r) => r && typeof r.score === 'number')).toBe(true);
|
|
47
|
-
expect(results.every((r) => r && r.score >= 0 && r.score <= 1)).toBe(true);
|
|
48
|
-
|
|
49
|
-
// Use expect-chain for loose verification
|
|
50
|
-
const [isValidToolScoring] = await aiExpect(
|
|
51
|
-
results,
|
|
52
|
-
undefined,
|
|
53
|
-
'Do these tool centrality scores make sense? Basic hand tools like hammer, screwdriver, wrench should have high scores, while chainsaw (power tool) should have a lower score.'
|
|
54
|
-
);
|
|
55
|
-
expect(isValidToolScoring).toBe(true);
|
|
56
|
-
},
|
|
57
|
-
longTestTimeout
|
|
58
|
-
);
|
|
59
|
-
|
|
60
|
-
it(
|
|
61
|
-
'demonstrates context effects on centrality',
|
|
62
|
-
async () => {
|
|
63
|
-
const items = ['robin', 'eagle', 'penguin', 'ostrich'];
|
|
64
|
-
const seedItems = ['robin', 'sparrow', 'cardinal', 'blue jay'];
|
|
65
|
-
|
|
66
|
-
const results = await bulkCentralTendency(items, seedItems, {
|
|
67
|
-
context: 'Small songbirds commonly seen in backyards',
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
expect(results).toHaveLength(4);
|
|
71
|
-
expect(results.every((r) => r && typeof r.score === 'number')).toBe(true);
|
|
72
|
-
|
|
73
|
-
// Use expect-chain for loose verification
|
|
74
|
-
const [isValidBirdScoring] = await aiExpect(
|
|
75
|
-
results,
|
|
76
|
-
undefined,
|
|
77
|
-
'Given the context of "small songbirds commonly seen in backyards", does robin have the highest centrality score, while penguin and ostrich have much lower scores?'
|
|
78
|
-
);
|
|
79
|
-
expect(isValidBirdScoring).toBe(true);
|
|
80
|
-
},
|
|
81
|
-
longTestTimeout
|
|
82
|
-
);
|
|
83
|
-
|
|
84
|
-
it(
|
|
85
|
-
'manages retry logic for failed items',
|
|
86
|
-
async () => {
|
|
87
|
-
const items = ['cat', 'dog', 'elephant'];
|
|
88
|
-
const seedItems = ['cat', 'dog', 'rabbit', 'hamster'];
|
|
89
|
-
|
|
90
|
-
const results = await bulkCentralTendency(items, seedItems, {
|
|
91
|
-
maxAttempts: 2,
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
expect(results).toHaveLength(3);
|
|
95
|
-
expect(results.every((r) => r && typeof r.score === 'number')).toBe(true);
|
|
96
|
-
|
|
97
|
-
// Use expect-chain for loose verification
|
|
98
|
-
const [isValidPetScoring] = await aiExpect(
|
|
99
|
-
results,
|
|
100
|
-
undefined,
|
|
101
|
-
'Are these reasonable centrality scores for pets, with cat and dog having higher scores than elephant?'
|
|
102
|
-
);
|
|
103
|
-
expect(isValidPetScoring).toBe(true);
|
|
104
|
-
},
|
|
105
|
-
longTestTimeout
|
|
106
|
-
);
|
|
107
|
-
|
|
108
|
-
it('handles empty input', async () => {
|
|
109
|
-
const results = await bulkCentralTendency([], ['apple', 'orange']);
|
|
110
|
-
expect(results).toEqual([]);
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
it('throws error for invalid seed items', async () => {
|
|
114
|
-
await expect(bulkCentralTendency(['apple'], [])).rejects.toThrow(
|
|
115
|
-
'seedItems must be a non-empty array'
|
|
116
|
-
);
|
|
117
|
-
await expect(bulkCentralTendency(['apple'], null)).rejects.toThrow(
|
|
118
|
-
'seedItems must be a non-empty array'
|
|
119
|
-
);
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
it(
|
|
123
|
-
'processes large batches efficiently',
|
|
124
|
-
async () => {
|
|
125
|
-
const items = Array.from({ length: 15 }, (_, i) => `item${i + 1}`);
|
|
126
|
-
const seedItems = ['item1', 'item2', 'item3', 'item4', 'item5'];
|
|
127
|
-
|
|
128
|
-
const results = await bulkCentralTendency(items, seedItems, {
|
|
129
|
-
chunkSize: 3,
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
expect(results).toHaveLength(15);
|
|
133
|
-
expect(results.every((r) => r && typeof r.score === 'number')).toBe(true);
|
|
134
|
-
expect(results.every((r) => r && r.score >= 0 && r.score <= 1)).toBe(true);
|
|
135
|
-
},
|
|
136
|
-
longTestTimeout
|
|
137
|
-
);
|
|
138
|
-
});
|
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
import { bulkMapRetry } from '../bulk-map/index.js';
|
|
2
|
-
import { CENTRAL_TENDENCY_PROMPT } from '../../verblets/central-tendency/index.js';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Build instructions for bulk central tendency evaluation using the core verblet prompt
|
|
6
|
-
* @param {string[]} seedItems - Array of seed items for comparison
|
|
7
|
-
* @param {Object} config - Configuration options
|
|
8
|
-
* @returns {string} Instructions for the bulk mapper
|
|
9
|
-
*/
|
|
10
|
-
function buildBulkCentralTendencyInstructions(seedItems, { context = '', coreFeatures = [] } = {}) {
|
|
11
|
-
const contextLine = context ? `Context: ${context}` : '';
|
|
12
|
-
const coreFeaturesLine =
|
|
13
|
-
coreFeatures.length > 0 ? `Core Features: ${coreFeatures.join(', ')}` : '';
|
|
14
|
-
const outputRequirementsLine = `OUTPUT FORMAT: Return exactly one compact JSON object per line (no line breaks within the JSON):
|
|
15
|
-
{"score": <number>, "reason": "<brief explanation>", "confidence": <number>}`;
|
|
16
|
-
|
|
17
|
-
// Use the core prompt with all variables replaced
|
|
18
|
-
const corePrompt = CENTRAL_TENDENCY_PROMPT.replace('{context}', contextLine)
|
|
19
|
-
.replace('{coreFeatures}', coreFeaturesLine)
|
|
20
|
-
.replace('{outputRequirements}', outputRequirementsLine);
|
|
21
|
-
|
|
22
|
-
return `For each item, evaluate its centrality among these category members: ${seedItems.join(
|
|
23
|
-
', '
|
|
24
|
-
)}
|
|
25
|
-
|
|
26
|
-
${corePrompt}`;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Process multiple items for central tendency evaluation in bulk with retry support.
|
|
31
|
-
* Uses the existing bulkMapRetry infrastructure for efficiency and reliability.
|
|
32
|
-
*
|
|
33
|
-
* @param {string[]} items - Array of items to evaluate
|
|
34
|
-
* @param {string[]} seedItems - Array of seed items for comparison
|
|
35
|
-
* @param {Object} [config={}] - Configuration options
|
|
36
|
-
* @param {string} [config.context=''] - Context description for evaluation
|
|
37
|
-
* @param {string[]} [config.coreFeatures=[]] - Known core/definitional features
|
|
38
|
-
* @param {string|Object} [config.llm='fastGoodCheap'] - LLM model to use
|
|
39
|
-
* @param {number} [config.chunkSize=5] - Batch size for processing
|
|
40
|
-
* @param {number} [config.maxAttempts=3] - Max retry attempts for failed items
|
|
41
|
-
* @returns {Promise<Array>} Array of central tendency results
|
|
42
|
-
*/
|
|
43
|
-
export default async function bulkCentralTendency(items, seedItems, config = {}) {
|
|
44
|
-
if (!Array.isArray(items)) {
|
|
45
|
-
throw new Error('Items must be an array');
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
if (items.length === 0) {
|
|
49
|
-
return [];
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
if (!Array.isArray(seedItems) || seedItems.length === 0) {
|
|
53
|
-
throw new Error('seedItems must be a non-empty array');
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
const { chunkSize = 5, maxAttempts = 3, ...otherConfig } = config;
|
|
57
|
-
|
|
58
|
-
// Build instructions for the bulk mapper
|
|
59
|
-
const instructions = buildBulkCentralTendencyInstructions(seedItems, otherConfig);
|
|
60
|
-
|
|
61
|
-
// Use bulkMapRetry to handle all the complexity
|
|
62
|
-
const results = await bulkMapRetry(items, instructions, { chunkSize, maxAttempts });
|
|
63
|
-
|
|
64
|
-
// Parse JSON responses and handle any parsing errors
|
|
65
|
-
return results.map((result, _index) => {
|
|
66
|
-
if (result === undefined) {
|
|
67
|
-
return undefined;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
try {
|
|
71
|
-
const parsed = JSON.parse(result);
|
|
72
|
-
|
|
73
|
-
// Validate the structure
|
|
74
|
-
if (
|
|
75
|
-
parsed &&
|
|
76
|
-
typeof parsed.score === 'number' &&
|
|
77
|
-
typeof parsed.reason === 'string' &&
|
|
78
|
-
typeof parsed.confidence === 'number'
|
|
79
|
-
) {
|
|
80
|
-
return parsed;
|
|
81
|
-
} else {
|
|
82
|
-
return undefined;
|
|
83
|
-
}
|
|
84
|
-
} catch {
|
|
85
|
-
return undefined;
|
|
86
|
-
}
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
// Export the retry version as well for consistency with other bulk processors
|
|
91
|
-
export const bulkCentralTendencyRetry = bulkCentralTendency;
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
# bulk-filter
|
|
2
|
-
|
|
3
|
-
Filter very long lists in manageable chunks using `listFilter`. Failed batches can be retried.
|
|
4
|
-
|
|
5
|
-
```javascript
|
|
6
|
-
import bulkFilter from './index.js';
|
|
7
|
-
|
|
8
|
-
const diary = [
|
|
9
|
-
'Walked the dog and bought milk.',
|
|
10
|
-
'One day I hope to sail across the Atlantic.',
|
|
11
|
-
'Cleaned out the garage.',
|
|
12
|
-
"Maybe I'll start that bakery I keep dreaming about.",
|
|
13
|
-
];
|
|
14
|
-
|
|
15
|
-
const aspirations = await bulkFilter(
|
|
16
|
-
diary,
|
|
17
|
-
'Keep only lines about hopes or big dreams',
|
|
18
|
-
{ chunkSize: 2 }
|
|
19
|
-
);
|
|
20
|
-
// => ['One day I hope to sail across the Atlantic.', "Maybe I'll start that bakery I keep dreaming about."]
|
|
21
|
-
```
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } 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 with listFilter',
|
|
8
|
-
async () => {
|
|
9
|
-
const notes = [
|
|
10
|
-
'Saw a dolphin while surfing',
|
|
11
|
-
'Finished laundry',
|
|
12
|
-
'Dream of traveling to Iceland',
|
|
13
|
-
'Paid the electricity bill',
|
|
14
|
-
];
|
|
15
|
-
const dreams = await bulkFilter(notes, 'keep only lines about aspirations or dreams', {
|
|
16
|
-
chunkSize: 2,
|
|
17
|
-
});
|
|
18
|
-
expect(dreams.length).toBeGreaterThan(0);
|
|
19
|
-
},
|
|
20
|
-
longTestTimeout
|
|
21
|
-
);
|
|
22
|
-
});
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import listFilter from '../../verblets/list-filter/index.js';
|
|
2
|
-
|
|
3
|
-
const buildMask = async (list, instructions, chunkSize, config = {}) => {
|
|
4
|
-
const mask = new Array(list.length);
|
|
5
|
-
for (let i = 0; i < list.length; i += chunkSize) {
|
|
6
|
-
const batch = list.slice(i, i + chunkSize);
|
|
7
|
-
try {
|
|
8
|
-
// eslint-disable-next-line no-await-in-loop
|
|
9
|
-
const result = await listFilter(batch, instructions, config);
|
|
10
|
-
const valid = result.every((item) => batch.includes(item));
|
|
11
|
-
if (!valid) {
|
|
12
|
-
for (let j = 0; j < batch.length; j += 1) {
|
|
13
|
-
mask[i + j] = undefined;
|
|
14
|
-
}
|
|
15
|
-
continue;
|
|
16
|
-
}
|
|
17
|
-
for (let j = 0; j < batch.length; j += 1) {
|
|
18
|
-
mask[i + j] = result.includes(batch[j]);
|
|
19
|
-
}
|
|
20
|
-
} catch {
|
|
21
|
-
for (let j = 0; j < batch.length; j += 1) {
|
|
22
|
-
mask[i + j] = undefined;
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
return mask;
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
export const bulkFilterRetry = async (list, instructions, config = {}) => {
|
|
30
|
-
const { chunkSize = 10, maxAttempts = 3, llm, ...options } = config;
|
|
31
|
-
const filterConfig = { llm, ...options };
|
|
32
|
-
let mask = await buildMask(list, instructions, chunkSize, filterConfig);
|
|
33
|
-
for (let attempt = 1; attempt < maxAttempts; attempt += 1) {
|
|
34
|
-
const missingIdx = [];
|
|
35
|
-
const missingItems = [];
|
|
36
|
-
mask.forEach((val, idx) => {
|
|
37
|
-
if (val === undefined) {
|
|
38
|
-
missingIdx.push(idx);
|
|
39
|
-
missingItems.push(list[idx]);
|
|
40
|
-
}
|
|
41
|
-
});
|
|
42
|
-
if (missingItems.length === 0) break;
|
|
43
|
-
// eslint-disable-next-line no-await-in-loop
|
|
44
|
-
const retryMask = await buildMask(missingItems, instructions, chunkSize, filterConfig);
|
|
45
|
-
retryMask.forEach((val, i) => {
|
|
46
|
-
if (val !== undefined) {
|
|
47
|
-
mask[missingIdx[i]] = val;
|
|
48
|
-
}
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
|
-
return list.filter((_, idx) => mask[idx]);
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
export default async function bulkFilter(list, instructions, config = {}) {
|
|
55
|
-
const { chunkSize = 10, llm, ...options } = config;
|
|
56
|
-
const mask = await buildMask(list, instructions, chunkSize, { llm, ...options });
|
|
57
|
-
return list.filter((_, idx) => mask[idx]);
|
|
58
|
-
}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { beforeEach, describe, expect, it, vi } 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 items in batches', async () => {
|
|
18
|
-
const result = await bulkFilter(['a', 'b', 'c'], 'a', { chunkSize: 2 });
|
|
19
|
-
expect(result).toStrictEqual(['a']);
|
|
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(['FAIL', 'a', 'b'], 'a', {
|
|
32
|
-
chunkSize: 2,
|
|
33
|
-
maxAttempts: 2,
|
|
34
|
-
});
|
|
35
|
-
expect(result).toStrictEqual(['a']);
|
|
36
|
-
expect(listFilter).toHaveBeenCalledTimes(3);
|
|
37
|
-
});
|
|
38
|
-
});
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
# bulk-find
|
|
2
|
-
|
|
3
|
-
Scan long lists in manageable batches to locate the item that best matches your instructions.
|
|
4
|
-
|
|
5
|
-
```javascript
|
|
6
|
-
import bulkFind from './index.js';
|
|
7
|
-
|
|
8
|
-
const emails = [
|
|
9
|
-
'update from accounting',
|
|
10
|
-
'party invitation',
|
|
11
|
-
'weekly newsletter',
|
|
12
|
-
// ... potentially thousands more
|
|
13
|
-
];
|
|
14
|
-
const best = await bulkFind(emails, 'Which email is most urgent?');
|
|
15
|
-
// => 'update from accounting'
|
|
16
|
-
```
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest';
|
|
2
|
-
import bulkFind from './index.js';
|
|
3
|
-
import { longTestTimeout } from '../../constants/common.js';
|
|
4
|
-
|
|
5
|
-
describe('bulk-find examples', () => {
|
|
6
|
-
it(
|
|
7
|
-
'finds the best match across batches',
|
|
8
|
-
async () => {
|
|
9
|
-
const titles = [
|
|
10
|
-
'ancient mystery',
|
|
11
|
-
'space odyssey',
|
|
12
|
-
'underwater adventure',
|
|
13
|
-
'future tech thriller',
|
|
14
|
-
];
|
|
15
|
-
const result = await bulkFind(titles, 'Which title feels most futuristic?', { chunkSize: 2 });
|
|
16
|
-
expect(result).toBeDefined();
|
|
17
|
-
},
|
|
18
|
-
longTestTimeout
|
|
19
|
-
);
|
|
20
|
-
});
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import listFind from '../../verblets/list-find/index.js';
|
|
2
|
-
|
|
3
|
-
export const bulkFind = async function (list, instructions, config = {}) {
|
|
4
|
-
const { chunkSize = 10, llm, ...options } = config;
|
|
5
|
-
let candidate = '';
|
|
6
|
-
for (let i = 0; i < list.length; i += chunkSize) {
|
|
7
|
-
const batch = list.slice(i, i + chunkSize);
|
|
8
|
-
const combined = candidate ? [candidate, ...batch] : batch;
|
|
9
|
-
// eslint-disable-next-line no-await-in-loop
|
|
10
|
-
candidate = await listFind(combined, instructions, { llm, ...options });
|
|
11
|
-
}
|
|
12
|
-
return candidate;
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
export const bulkFindRetry = async function (list, instructions, config = {}) {
|
|
16
|
-
const { chunkSize = 10, maxAttempts = 3, llm, ...options } = config;
|
|
17
|
-
let result;
|
|
18
|
-
for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
|
|
19
|
-
try {
|
|
20
|
-
// eslint-disable-next-line no-await-in-loop
|
|
21
|
-
result = await bulkFind(list, instructions, { chunkSize, llm, ...options });
|
|
22
|
-
if (result) break;
|
|
23
|
-
} catch {
|
|
24
|
-
// continue
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
return result;
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
export default bulkFind;
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { beforeEach, describe, expect, it, vi } 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 (items) => items[items.length - 1]),
|
|
7
|
-
}));
|
|
8
|
-
|
|
9
|
-
beforeEach(() => {
|
|
10
|
-
vi.clearAllMocks();
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
describe('bulk-find chain', () => {
|
|
14
|
-
it('scans batches to find best item', async () => {
|
|
15
|
-
const result = await bulkFind(['a', 'b', 'c', 'd'], 'find', { chunkSize: 2 });
|
|
16
|
-
expect(result).toBe('d');
|
|
17
|
-
expect(listFind).toHaveBeenCalledTimes(2);
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
it('retries on failure', async () => {
|
|
21
|
-
listFind.mockRejectedValueOnce(new Error('fail'));
|
|
22
|
-
const result = await bulkFindRetry(['x', 'y'], 'find', { chunkSize: 2, maxAttempts: 2 });
|
|
23
|
-
expect(result).toBe('y');
|
|
24
|
-
expect(listFind).toHaveBeenCalledTimes(2);
|
|
25
|
-
});
|
|
26
|
-
});
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
# bulk-group
|
|
2
|
-
|
|
3
|
-
Group long lists by first discovering the best categories and then grouping
|
|
4
|
-
items into those categories in smaller batches.
|
|
5
|
-
|
|
6
|
-
```javascript
|
|
7
|
-
import bulkGroup from './index.js';
|
|
8
|
-
|
|
9
|
-
const feedback = [
|
|
10
|
-
'Great interface and onboarding',
|
|
11
|
-
'Price is a bit steep',
|
|
12
|
-
'Love the mobile app',
|
|
13
|
-
'Needs more integrations',
|
|
14
|
-
];
|
|
15
|
-
const result = await bulkGroup(
|
|
16
|
-
feedback,
|
|
17
|
-
'Is each line praise, criticism, or a feature request?',
|
|
18
|
-
{ chunkSize: 2, topN: 3 }
|
|
19
|
-
);
|
|
20
|
-
// => { praise: ['Great interface and onboarding', 'Love the mobile app'],
|
|
21
|
-
// criticism: ['Price is a bit steep'],
|
|
22
|
-
// 'feature request': ['Needs more integrations'] }
|
|
23
|
-
```
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import bulkGroup from './index.js';
|
|
2
|
-
import { describe, it, expect } from 'vitest';
|
|
3
|
-
import { longTestTimeout } from '../../constants/common.js';
|
|
4
|
-
|
|
5
|
-
describe('bulk-group examples', () => {
|
|
6
|
-
it(
|
|
7
|
-
'groups a long list',
|
|
8
|
-
async () => {
|
|
9
|
-
const items = ['dog', 'fish', 'cat', 'whale', 'bird', 'shark', 'horse', 'dolphin'];
|
|
10
|
-
const result = await bulkGroup(items, 'Is each creature terrestrial or aquatic?', {
|
|
11
|
-
chunkSize: 4,
|
|
12
|
-
});
|
|
13
|
-
expect(typeof result).toBe('object');
|
|
14
|
-
expect(Object.keys(result).length).toBeGreaterThan(0);
|
|
15
|
-
},
|
|
16
|
-
longTestTimeout
|
|
17
|
-
);
|
|
18
|
-
});
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import listGroup from '../../verblets/list-group/index.js';
|
|
2
|
-
|
|
3
|
-
export default async function bulkGroup(list, instructions, config = {}) {
|
|
4
|
-
const { chunkSize = 10, topN, llm, ...options } = config;
|
|
5
|
-
let categories;
|
|
6
|
-
const groups = {};
|
|
7
|
-
|
|
8
|
-
for (let i = 0; i < list.length; i += chunkSize) {
|
|
9
|
-
const batch = list.slice(i, i + chunkSize);
|
|
10
|
-
|
|
11
|
-
// eslint-disable-next-line no-await-in-loop
|
|
12
|
-
const result = await listGroup(batch, instructions, categories, { llm, ...options });
|
|
13
|
-
|
|
14
|
-
// Use categories from first batch for consistency
|
|
15
|
-
if (!categories) {
|
|
16
|
-
categories = Object.keys(result);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
for (const [key, items] of Object.entries(result)) {
|
|
20
|
-
if (!groups[key]) groups[key] = [];
|
|
21
|
-
groups[key].push(...items);
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
// Apply topN filtering if specified
|
|
26
|
-
if (topN) {
|
|
27
|
-
const sortedEntries = Object.entries(groups)
|
|
28
|
-
.sort(([, a], [, b]) => b.length - a.length)
|
|
29
|
-
.slice(0, topN);
|
|
30
|
-
return Object.fromEntries(sortedEntries);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
return groups;
|
|
34
|
-
}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import bulkGroup from './index.js';
|
|
2
|
-
import listGroup from '../../verblets/list-group/index.js';
|
|
3
|
-
import { vi, describe, it, expect, beforeEach } from 'vitest';
|
|
4
|
-
|
|
5
|
-
vi.mock('../../verblets/list-group/index.js', () => ({
|
|
6
|
-
default: vi.fn(),
|
|
7
|
-
}));
|
|
8
|
-
|
|
9
|
-
describe('bulk-group chain', () => {
|
|
10
|
-
beforeEach(() => {
|
|
11
|
-
vi.clearAllMocks();
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
it('groups in batches', async () => {
|
|
15
|
-
const items = ['a', 'bb', 'ccc', 'dddd', 'eeeee'];
|
|
16
|
-
|
|
17
|
-
// Mock the calls in order - with chunkSize=2, we'll have 3 batches: [a,bb], [ccc,dddd], [eeeee]
|
|
18
|
-
listGroup
|
|
19
|
-
.mockResolvedValueOnce({ odd: ['a'], even: ['bb'] }) // First batch
|
|
20
|
-
.mockResolvedValueOnce({ odd: ['ccc'], even: ['dddd'] }) // Second batch
|
|
21
|
-
.mockResolvedValueOnce({ odd: ['eeeee'] }); // Third batch
|
|
22
|
-
|
|
23
|
-
const result = await bulkGroup(items, 'odd or even', {
|
|
24
|
-
chunkSize: 2,
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
expect(result).toStrictEqual({ odd: ['a', 'ccc', 'eeeee'], even: ['bb', 'dddd'] });
|
|
28
|
-
expect(listGroup).toHaveBeenCalledTimes(3);
|
|
29
|
-
|
|
30
|
-
// Verify the calls were made with the right parameters
|
|
31
|
-
expect(listGroup).toHaveBeenNthCalledWith(1, ['a', 'bb'], 'odd or even', undefined, {
|
|
32
|
-
llm: undefined,
|
|
33
|
-
});
|
|
34
|
-
expect(listGroup).toHaveBeenNthCalledWith(2, ['ccc', 'dddd'], 'odd or even', ['odd', 'even'], {
|
|
35
|
-
llm: undefined,
|
|
36
|
-
});
|
|
37
|
-
expect(listGroup).toHaveBeenNthCalledWith(3, ['eeeee'], 'odd or even', ['odd', 'even'], {
|
|
38
|
-
llm: undefined,
|
|
39
|
-
});
|
|
40
|
-
});
|
|
41
|
-
});
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
# bulk-map
|
|
2
|
-
|
|
3
|
-
Chunk large lists and map each chunk with `listMap`. Failed chunks can be retried.
|
|
4
|
-
|
|
5
|
-
## Usage
|
|
6
|
-
|
|
7
|
-
```javascript
|
|
8
|
-
import { bulkMap } from '../../index.js';
|
|
9
|
-
|
|
10
|
-
const films = [
|
|
11
|
-
'sci-fi epic',
|
|
12
|
-
'romantic comedy',
|
|
13
|
-
'time-travel thriller',
|
|
14
|
-
// ...more titles
|
|
15
|
-
];
|
|
16
|
-
const results = await bulkMap(films, 'Describe each as a Shakespearean play', { chunkSize: 5 });
|
|
17
|
-
// results[0] === 'A saga among the stars'
|
|
18
|
-
// results[1] === 'Where hearts and humor entwine'
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
## API
|
|
22
|
-
|
|
23
|
-
### `bulkMap(list, instructions, [chunkSize])`
|
|
24
|
-
|
|
25
|
-
Break `list` into batches and map each batch using `listMap`.
|
|
26
|
-
|
|
27
|
-
- `list` (`string[]`): fragments to process.
|
|
28
|
-
- `instructions` (`string`): mapping instructions.
|
|
29
|
-
- `chunkSize` (`number`, default `10`): number of items per batch.
|
|
30
|
-
|
|
31
|
-
Returns `Promise<(string|undefined)[]>` where undefined entries represent failed items.
|
|
32
|
-
|
|
33
|
-
### `bulkMapRetry(list, instructions, [options])`
|
|
34
|
-
|
|
35
|
-
Retry undefined entries from `bulkMap` until `maxAttempts` is reached.
|
|
36
|
-
|
|
37
|
-
- `list` (`string[]`): fragments to process.
|
|
38
|
-
- `instructions` (`string`): mapping instructions.
|
|
39
|
-
- `options.chunkSize` (`number`, default `10`): size of each batch.
|
|
40
|
-
- `options.maxAttempts` (`number`, default `3`): number of passes over failed items.
|
|
41
|
-
|
|
42
|
-
Returns `Promise<(string|undefined)[]>` aligned with input order.
|
|
43
|
-
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest';
|
|
2
|
-
import bulkMap from './index.js';
|
|
3
|
-
import { longTestTimeout } from '../../constants/common.js';
|
|
4
|
-
|
|
5
|
-
describe('bulkmap examples', () => {
|
|
6
|
-
it(
|
|
7
|
-
'maps with listMap',
|
|
8
|
-
async () => {
|
|
9
|
-
const animals = ['dog', 'cat', 'cow', 'sheep', 'duck'];
|
|
10
|
-
const result = await bulkMap(animals, 'Return the sound each animal makes', { chunkSize: 3 });
|
|
11
|
-
// e.g. result[0] === 'bark'
|
|
12
|
-
// result[2] === 'moo'
|
|
13
|
-
expect(result.length).toBe(5);
|
|
14
|
-
},
|
|
15
|
-
longTestTimeout
|
|
16
|
-
);
|
|
17
|
-
});
|