@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.
Files changed (330) hide show
  1. package/README.md +86 -213
  2. package/dist/index.browser.js +74 -0
  3. package/dist/index.js +548 -0
  4. package/dist/shared-C6kPWghF.js +7806 -0
  5. package/package.json +32 -11
  6. package/.cursor/launch.json +0 -30
  7. package/.cursor/settings.json +0 -20
  8. package/.github/workflows/branch-protection.yml +0 -22
  9. package/.github/workflows/ci.yml +0 -165
  10. package/.husky/pre-commit +0 -4
  11. package/.prettierrc +0 -6
  12. package/.release-it.json +0 -12
  13. package/.vitest.config.examples.js +0 -12
  14. package/.vitest.config.js +0 -8
  15. package/.vscode/launch.json +0 -31
  16. package/AGENTS.md +0 -220
  17. package/DEVELOPING.md +0 -105
  18. package/docker-compose.yml +0 -7
  19. package/eslint.config.js +0 -80
  20. package/scripts/clear-redis.js +0 -74
  21. package/scripts/generate-chain/index.js +0 -111
  22. package/scripts/generate-lib/index.js +0 -68
  23. package/scripts/generate-test/index.js +0 -137
  24. package/scripts/generate-verblet/README.md +0 -17
  25. package/scripts/generate-verblet/index.js +0 -110
  26. package/scripts/run.sh +0 -15
  27. package/scripts/runner/index.js +0 -56
  28. package/scripts/simple-editor/README.md +0 -34
  29. package/scripts/simple-editor/index.js +0 -79
  30. package/scripts/summarize-files/index.js +0 -70
  31. package/src/chains/README.md +0 -30
  32. package/src/chains/anonymize/README.md +0 -21
  33. package/src/chains/anonymize/index.examples.js +0 -75
  34. package/src/chains/anonymize/index.js +0 -121
  35. package/src/chains/anonymize/index.spec.js +0 -78
  36. package/src/chains/bulk-central-tendency/index.examples.js +0 -138
  37. package/src/chains/bulk-central-tendency/index.js +0 -91
  38. package/src/chains/bulk-filter/README.md +0 -21
  39. package/src/chains/bulk-filter/index.examples.js +0 -22
  40. package/src/chains/bulk-filter/index.js +0 -58
  41. package/src/chains/bulk-filter/index.spec.js +0 -38
  42. package/src/chains/bulk-find/README.md +0 -16
  43. package/src/chains/bulk-find/index.examples.js +0 -20
  44. package/src/chains/bulk-find/index.js +0 -30
  45. package/src/chains/bulk-find/index.spec.js +0 -26
  46. package/src/chains/bulk-group/README.md +0 -23
  47. package/src/chains/bulk-group/index.examples.js +0 -18
  48. package/src/chains/bulk-group/index.js +0 -34
  49. package/src/chains/bulk-group/index.spec.js +0 -41
  50. package/src/chains/bulk-map/README.md +0 -43
  51. package/src/chains/bulk-map/index.examples.js +0 -17
  52. package/src/chains/bulk-map/index.js +0 -86
  53. package/src/chains/bulk-map/index.spec.js +0 -44
  54. package/src/chains/bulk-reduce/README.md +0 -12
  55. package/src/chains/bulk-reduce/index.examples.js +0 -15
  56. package/src/chains/bulk-reduce/index.js +0 -13
  57. package/src/chains/bulk-reduce/index.spec.js +0 -25
  58. package/src/chains/bulk-score/README.md +0 -16
  59. package/src/chains/bulk-score/bulk-score-result.json +0 -18
  60. package/src/chains/bulk-score/index.examples.js +0 -22
  61. package/src/chains/bulk-score/index.js +0 -133
  62. package/src/chains/bulk-score/index.spec.js +0 -30
  63. package/src/chains/category-samples/README.md +0 -61
  64. package/src/chains/category-samples/index.examples.js +0 -103
  65. package/src/chains/category-samples/index.js +0 -134
  66. package/src/chains/collect-terms/README.md +0 -12
  67. package/src/chains/collect-terms/index.examples.js +0 -16
  68. package/src/chains/collect-terms/index.js +0 -44
  69. package/src/chains/collect-terms/index.spec.js +0 -25
  70. package/src/chains/conversation/README.md +0 -26
  71. package/src/chains/conversation/index.examples.js +0 -398
  72. package/src/chains/conversation/index.js +0 -126
  73. package/src/chains/conversation/index.spec.js +0 -148
  74. package/src/chains/conversation/turn-policies.js +0 -93
  75. package/src/chains/conversation/turn-policies.md +0 -123
  76. package/src/chains/conversation/turn-policies.spec.js +0 -135
  77. package/src/chains/date/README.md +0 -12
  78. package/src/chains/date/index.examples.js +0 -47
  79. package/src/chains/date/index.js +0 -74
  80. package/src/chains/date/index.spec.js +0 -62
  81. package/src/chains/disambiguate/README.md +0 -22
  82. package/src/chains/disambiguate/disambiguate-meanings-result.json +0 -16
  83. package/src/chains/disambiguate/index.examples.js +0 -18
  84. package/src/chains/disambiguate/index.js +0 -92
  85. package/src/chains/disambiguate/index.spec.js +0 -25
  86. package/src/chains/dismantle/README.md +0 -67
  87. package/src/chains/dismantle/dismantle.examples.js +0 -27
  88. package/src/chains/dismantle/index.examples.js +0 -30
  89. package/src/chains/dismantle/index.js +0 -303
  90. package/src/chains/dismantle/index.spec.js +0 -32
  91. package/src/chains/expect/README.md +0 -171
  92. package/src/chains/expect/index.examples.js +0 -146
  93. package/src/chains/expect/index.js +0 -207
  94. package/src/chains/expect/index.spec.js +0 -324
  95. package/src/chains/filter-ambiguous/README.md +0 -11
  96. package/src/chains/filter-ambiguous/index.examples.js +0 -20
  97. package/src/chains/filter-ambiguous/index.js +0 -49
  98. package/src/chains/filter-ambiguous/index.spec.js +0 -31
  99. package/src/chains/glossary/README.md +0 -19
  100. package/src/chains/glossary/index.examples.js +0 -386
  101. package/src/chains/glossary/index.js +0 -75
  102. package/src/chains/glossary/index.spec.js +0 -19
  103. package/src/chains/intersections/README.md +0 -166
  104. package/src/chains/intersections/index.examples.js +0 -280
  105. package/src/chains/intersections/index.js +0 -218
  106. package/src/chains/intersections/intersection-result.json +0 -38
  107. package/src/chains/list/index.examples.js +0 -68
  108. package/src/chains/list/index.js +0 -214
  109. package/src/chains/list/index.spec.js +0 -67
  110. package/src/chains/list/list-result.json +0 -16
  111. package/src/chains/list/schema.json +0 -24
  112. package/src/chains/llm-logger/README.md +0 -366
  113. package/src/chains/llm-logger/index.js +0 -591
  114. package/src/chains/llm-logger/index.spec.js +0 -391
  115. package/src/chains/llm-logger/schema.json +0 -105
  116. package/src/chains/questions/index.examples.js +0 -69
  117. package/src/chains/questions/index.js +0 -135
  118. package/src/chains/questions/index.spec.js +0 -29
  119. package/src/chains/scan-js/index.js +0 -116
  120. package/src/chains/set-interval/README.md +0 -81
  121. package/src/chains/set-interval/index.examples.js +0 -64
  122. package/src/chains/set-interval/index.js +0 -152
  123. package/src/chains/set-interval/index.spec.js +0 -70
  124. package/src/chains/socratic/README.md +0 -17
  125. package/src/chains/socratic/index.js +0 -64
  126. package/src/chains/socratic/index.spec.js +0 -24
  127. package/src/chains/sort/index.examples.js +0 -36
  128. package/src/chains/sort/index.js +0 -163
  129. package/src/chains/sort/index.spec.js +0 -112
  130. package/src/chains/sort/sort-result.json +0 -16
  131. package/src/chains/summary-map/README.md +0 -41
  132. package/src/chains/summary-map/index.examples.js +0 -64
  133. package/src/chains/summary-map/index.js +0 -226
  134. package/src/chains/summary-map/index.spec.js +0 -153
  135. package/src/chains/test/index.js +0 -114
  136. package/src/chains/test-advice/index.js +0 -35
  137. package/src/chains/themes/README.md +0 -20
  138. package/src/chains/themes/index.examples.js +0 -17
  139. package/src/chains/themes/index.js +0 -28
  140. package/src/chains/themes/index.spec.js +0 -19
  141. package/src/chains/veiled-variants/index.examples.js +0 -18
  142. package/src/chains/veiled-variants/index.js +0 -107
  143. package/src/chains/veiled-variants/index.spec.js +0 -40
  144. package/src/constants/common.js +0 -13
  145. package/src/constants/messages.js +0 -3
  146. package/src/constants/models.js +0 -184
  147. package/src/index.js +0 -203
  148. package/src/json-schemas/README.md +0 -13
  149. package/src/json-schemas/cars-test.json +0 -11
  150. package/src/json-schemas/index.js +0 -12
  151. package/src/json-schemas/intent.json +0 -38
  152. package/src/json-schemas/schema-dot-org-photograph.json +0 -133
  153. package/src/json-schemas/schema-dot-org-place.json +0 -129
  154. package/src/lib/README.md +0 -26
  155. package/src/lib/any-signal/index.js +0 -28
  156. package/src/lib/assert/README.md +0 -84
  157. package/src/lib/assert/index.js +0 -50
  158. package/src/lib/bulk-filter/README.md +0 -22
  159. package/src/lib/bulk-filter/index.examples.js +0 -27
  160. package/src/lib/bulk-filter/index.js +0 -63
  161. package/src/lib/bulk-filter/index.spec.js +0 -38
  162. package/src/lib/bulk-find/README.md +0 -18
  163. package/src/lib/bulk-find/index.examples.js +0 -19
  164. package/src/lib/bulk-find/index.js +0 -30
  165. package/src/lib/bulk-find/index.spec.js +0 -41
  166. package/src/lib/chatgpt/index.js +0 -163
  167. package/src/lib/combinations/index.js +0 -30
  168. package/src/lib/combinations/index.spec.js +0 -23
  169. package/src/lib/editor/index.js +0 -31
  170. package/src/lib/functional/index.js +0 -28
  171. package/src/lib/logger-service/index.js +0 -32
  172. package/src/lib/parse-js-parts/index.js +0 -321
  173. package/src/lib/parse-js-parts/index.spec.js +0 -156
  174. package/src/lib/parse-llm-list/README.md +0 -39
  175. package/src/lib/parse-llm-list/index.js +0 -54
  176. package/src/lib/parse-llm-list/index.spec.js +0 -59
  177. package/src/lib/path-aliases/index.js +0 -37
  178. package/src/lib/path-aliases/index.spec.js +0 -64
  179. package/src/lib/pave/index.js +0 -34
  180. package/src/lib/pave/index.spec.js +0 -76
  181. package/src/lib/prompt-cache/index.js +0 -50
  182. package/src/lib/retry/index.js +0 -66
  183. package/src/lib/retry/index.spec.js +0 -86
  184. package/src/lib/ring-buffer/README.md +0 -82
  185. package/src/lib/ring-buffer/index.js +0 -235
  186. package/src/lib/ring-buffer/index.spec.js +0 -388
  187. package/src/lib/search-best-first/city-walk.spec.js +0 -37
  188. package/src/lib/search-best-first/index.js +0 -97
  189. package/src/lib/search-best-first/index.spec.js +0 -35
  190. package/src/lib/search-js-files/code-features-property-definitions.json +0 -123
  191. package/src/lib/search-js-files/index.examples.js +0 -22
  192. package/src/lib/search-js-files/index.js +0 -155
  193. package/src/lib/search-js-files/index.spec.js +0 -34
  194. package/src/lib/search-js-files/scan-file.js +0 -242
  195. package/src/lib/shorten-text/index.js +0 -25
  196. package/src/lib/shorten-text/index.spec.js +0 -68
  197. package/src/lib/strip-numeric/index.js +0 -5
  198. package/src/lib/strip-response/index.js +0 -30
  199. package/src/lib/template-replace/index.js +0 -23
  200. package/src/lib/template-replace/index.spec.js +0 -60
  201. package/src/lib/timed-abort-controller/index.js +0 -41
  202. package/src/lib/to-bool/index.js +0 -8
  203. package/src/lib/to-date/index.js +0 -11
  204. package/src/lib/to-enum/index.js +0 -14
  205. package/src/lib/to-number/index.js +0 -12
  206. package/src/lib/to-number-with-units/index.js +0 -51
  207. package/src/lib/transcribe/index.js +0 -78
  208. package/src/prompts/README.md +0 -17
  209. package/src/prompts/as-enum.js +0 -5
  210. package/src/prompts/as-json-schema.js +0 -9
  211. package/src/prompts/as-object-with-schema.js +0 -26
  212. package/src/prompts/as-schema-org-text.js +0 -25
  213. package/src/prompts/as-schema-org-type.js +0 -1
  214. package/src/prompts/blog-post.js +0 -7
  215. package/src/prompts/code-features.js +0 -24
  216. package/src/prompts/constants.js +0 -101
  217. package/src/prompts/features-json-schema.js +0 -27
  218. package/src/prompts/generate-collection.js +0 -26
  219. package/src/prompts/generate-list.js +0 -48
  220. package/src/prompts/generate-questions.js +0 -19
  221. package/src/prompts/index.js +0 -20
  222. package/src/prompts/intent.js +0 -60
  223. package/src/prompts/output-succinct-names.js +0 -3
  224. package/src/prompts/select-from-threshold.js +0 -17
  225. package/src/prompts/sort.js +0 -31
  226. package/src/prompts/style.js +0 -38
  227. package/src/prompts/summarize.js +0 -13
  228. package/src/prompts/token-budget.js +0 -3
  229. package/src/prompts/wrap-list.js +0 -11
  230. package/src/prompts/wrap-variable.js +0 -36
  231. package/src/services/llm-model/global-overrides.spec.js +0 -432
  232. package/src/services/llm-model/index.js +0 -308
  233. package/src/services/llm-model/model.js +0 -21
  234. package/src/services/llm-model/negotiate.spec.js +0 -447
  235. package/src/services/redis/index.js +0 -147
  236. package/src/test/setup.js +0 -20
  237. package/src/verblets/README.md +0 -26
  238. package/src/verblets/auto/index.examples.js +0 -31
  239. package/src/verblets/auto/index.js +0 -28
  240. package/src/verblets/auto/index.spec.js +0 -32
  241. package/src/verblets/bool/README.md +0 -36
  242. package/src/verblets/bool/index.examples.js +0 -80
  243. package/src/verblets/bool/index.js +0 -25
  244. package/src/verblets/bool/index.schema.json +0 -14
  245. package/src/verblets/bool/index.spec.js +0 -33
  246. package/src/verblets/central-tendency/README.md +0 -166
  247. package/src/verblets/central-tendency/central-tendency-result.json +0 -24
  248. package/src/verblets/central-tendency/index.examples.js +0 -196
  249. package/src/verblets/central-tendency/index.js +0 -171
  250. package/src/verblets/central-tendency/index.spec.js +0 -148
  251. package/src/verblets/conversation-turn/README.md +0 -33
  252. package/src/verblets/conversation-turn/index.examples.js +0 -218
  253. package/src/verblets/conversation-turn/index.js +0 -68
  254. package/src/verblets/conversation-turn/index.spec.js +0 -77
  255. package/src/verblets/conversation-turn-multi/README.md +0 -31
  256. package/src/verblets/conversation-turn-multi/index.examples.js +0 -160
  257. package/src/verblets/conversation-turn-multi/index.js +0 -104
  258. package/src/verblets/conversation-turn-multi/index.spec.js +0 -63
  259. package/src/verblets/enum/index.examples.js +0 -30
  260. package/src/verblets/enum/index.js +0 -18
  261. package/src/verblets/enum/index.spec.js +0 -35
  262. package/src/verblets/expect/README.md +0 -64
  263. package/src/verblets/expect/index.examples.js +0 -109
  264. package/src/verblets/expect/index.js +0 -75
  265. package/src/verblets/expect/index.spec.js +0 -127
  266. package/src/verblets/intent/index.examples.js +0 -139
  267. package/src/verblets/intent/index.js +0 -60
  268. package/src/verblets/intent/index.spec.js +0 -31
  269. package/src/verblets/intersection/README.md +0 -16
  270. package/src/verblets/intersection/index.examples.js +0 -89
  271. package/src/verblets/intersection/index.js +0 -125
  272. package/src/verblets/intersection/index.spec.js +0 -60
  273. package/src/verblets/intersection/intersection-result.json +0 -16
  274. package/src/verblets/list-expand/README.md +0 -10
  275. package/src/verblets/list-expand/index.examples.js +0 -14
  276. package/src/verblets/list-expand/index.js +0 -104
  277. package/src/verblets/list-expand/index.spec.js +0 -18
  278. package/src/verblets/list-expand/list-expand-result.json +0 -16
  279. package/src/verblets/list-filter/README.md +0 -22
  280. package/src/verblets/list-filter/index.examples.js +0 -26
  281. package/src/verblets/list-filter/index.js +0 -18
  282. package/src/verblets/list-filter/index.spec.js +0 -19
  283. package/src/verblets/list-find/README.md +0 -11
  284. package/src/verblets/list-find/index.examples.js +0 -15
  285. package/src/verblets/list-find/index.js +0 -17
  286. package/src/verblets/list-find/index.spec.js +0 -19
  287. package/src/verblets/list-group/README.md +0 -16
  288. package/src/verblets/list-group/index.examples.js +0 -16
  289. package/src/verblets/list-group/index.js +0 -112
  290. package/src/verblets/list-group/index.spec.js +0 -35
  291. package/src/verblets/list-group/list-group-result.json +0 -16
  292. package/src/verblets/list-map/README.md +0 -11
  293. package/src/verblets/list-map/index.examples.js +0 -15
  294. package/src/verblets/list-map/index.js +0 -26
  295. package/src/verblets/list-map/index.spec.js +0 -17
  296. package/src/verblets/list-reduce/README.md +0 -10
  297. package/src/verblets/list-reduce/index.examples.js +0 -14
  298. package/src/verblets/list-reduce/index.js +0 -21
  299. package/src/verblets/list-reduce/index.spec.js +0 -27
  300. package/src/verblets/list-reduce/index.spec.jsx +0 -27
  301. package/src/verblets/name/README.md +0 -15
  302. package/src/verblets/name/index.examples.js +0 -28
  303. package/src/verblets/name/index.js +0 -19
  304. package/src/verblets/name/index.spec.js +0 -33
  305. package/src/verblets/name-similar-to/README.md +0 -26
  306. package/src/verblets/name-similar-to/index.examples.js +0 -18
  307. package/src/verblets/name-similar-to/index.js +0 -20
  308. package/src/verblets/name-similar-to/index.spec.js +0 -13
  309. package/src/verblets/number/index.examples.js +0 -199
  310. package/src/verblets/number/index.js +0 -25
  311. package/src/verblets/number/index.spec.js +0 -33
  312. package/src/verblets/number-with-units/index.examples.js +0 -38
  313. package/src/verblets/number-with-units/index.js +0 -84
  314. package/src/verblets/number-with-units/index.spec.js +0 -46
  315. package/src/verblets/number-with-units/number-with-units-result.json +0 -23
  316. package/src/verblets/people-list/README.md +0 -28
  317. package/src/verblets/people-list/index.examples.js +0 -184
  318. package/src/verblets/people-list/index.js +0 -44
  319. package/src/verblets/people-list/index.spec.js +0 -49
  320. package/src/verblets/schema-org/index.examples.js +0 -51
  321. package/src/verblets/schema-org/index.js +0 -37
  322. package/src/verblets/schema-org/index.spec.js +0 -39
  323. package/src/verblets/sentiment/README.md +0 -10
  324. package/src/verblets/sentiment/index.examples.js +0 -20
  325. package/src/verblets/sentiment/index.js +0 -9
  326. package/src/verblets/sentiment/index.spec.js +0 -20
  327. package/src/verblets/to-object/README.md +0 -38
  328. package/src/verblets/to-object/index.examples.js +0 -29
  329. package/src/verblets/to-object/index.js +0 -131
  330. 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
- });