@far-world-labs/verblets 0.2.0 → 0.4.0

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 +98 -213
  2. package/dist/index.browser.js +221 -0
  3. package/dist/index.js +696 -0
  4. package/dist/shared-CMgpfDG4.js +10714 -0
  5. package/package.json +38 -15
  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,86 +0,0 @@
1
- import listMap from '../../verblets/list-map/index.js';
2
-
3
- /**
4
- * Map over a list of fragments by calling `listMap` on newline-delimited batches.
5
- * Missing or mismatched output results in `undefined` entries so callers can
6
- * selectively retry.
7
- *
8
- * @param { string[] } list - array of fragments to process
9
- * @param { string } instructions - mapping instructions passed to `listMap`
10
- * @param { object } [config={}] - configuration options
11
- * @param { number } [config.chunkSize=10] - how many items to send per batch
12
- * @param { object } [config.llm] - LLM configuration
13
- * @returns { Promise<(string|undefined)[]> } results aligned with input order
14
- */
15
- const bulkMap = async function (list, instructions, config = {}) {
16
- const { chunkSize = 10, llm, ...options } = config;
17
- const results = new Array(list.length);
18
- const promises = [];
19
-
20
- for (let i = 0; i < list.length; i += chunkSize) {
21
- const batch = list.slice(i, i + chunkSize);
22
- const startIndex = i;
23
-
24
- const p = Promise.resolve()
25
- .then(() => listMap(batch, instructions, { llm, ...options }))
26
- .then((output) => {
27
- if (output.length !== batch.length) {
28
- for (let j = 0; j < batch.length; j += 1) {
29
- results[startIndex + j] = undefined;
30
- }
31
- return;
32
- }
33
- output.forEach((line, j) => {
34
- results[startIndex + j] = line;
35
- });
36
- })
37
- .catch(() => {
38
- for (let j = 0; j < batch.length; j += 1) {
39
- results[startIndex + j] = undefined;
40
- }
41
- });
42
- promises.push(p);
43
- }
44
-
45
- await Promise.all(promises);
46
- return results;
47
- };
48
-
49
- /**
50
- * Retry only the undefined results from `map` until maxAttempts is reached.
51
- *
52
- * @param { string[] } list - array of fragments
53
- * @param { string } instructions - mapping instructions passed to `listMap`
54
- * @param { object } [config={}] - configuration options
55
- * @param { number } [config.chunkSize=10]
56
- * @param { number } [config.maxAttempts=3]
57
- * @param { object } [config.llm] - LLM configuration
58
- * @returns { Promise<(string|undefined)[]> }
59
- */
60
- export const bulkMapRetry = async function (list, instructions, config = {}) {
61
- const { chunkSize = 10, maxAttempts = 3, llm, ...options } = config;
62
- const results = await bulkMap(list, instructions, { chunkSize, llm, ...options });
63
- for (let attempt = 1; attempt < maxAttempts; attempt += 1) {
64
- const missingIdx = [];
65
- const missingFragments = [];
66
- results.forEach((val, idx) => {
67
- if (val === undefined) {
68
- missingIdx.push(idx);
69
- missingFragments.push(list[idx]);
70
- }
71
- });
72
- if (missingFragments.length === 0) break;
73
- // eslint-disable-next-line no-await-in-loop
74
- const retryResults = await bulkMap(missingFragments, instructions, {
75
- chunkSize,
76
- llm,
77
- ...options,
78
- });
79
- retryResults.forEach((val, i) => {
80
- results[missingIdx[i]] = val;
81
- });
82
- }
83
- return results;
84
- };
85
-
86
- export default bulkMap;
@@ -1,44 +0,0 @@
1
- import { beforeEach, describe, expect, it, vi } from 'vitest';
2
- import bulkMap, { bulkMapRetry } from './index.js';
3
- import listMap from '../../verblets/list-map/index.js';
4
-
5
- vi.mock('../../verblets/list-map/index.js', () => ({
6
- default: vi.fn(async (items, instructions) => {
7
- if (items.includes('FAIL')) throw new Error('fail');
8
- return items.map((i) => `${i}-${instructions}`);
9
- }),
10
- }));
11
-
12
- beforeEach(() => {
13
- vi.clearAllMocks();
14
- });
15
-
16
- describe('bulkmap', () => {
17
- it('maps fragments in batches', async () => {
18
- const result = await bulkMap(['a', 'b', 'c'], 'x', { chunkSize: 2 });
19
- expect(result).toStrictEqual(['a-x', 'b-x', 'c-x']);
20
- expect(listMap).toHaveBeenCalledTimes(2);
21
- });
22
-
23
- it('leaves undefined on error', async () => {
24
- listMap.mockRejectedValueOnce(new Error('fail'));
25
- const result = await bulkMap(['FAIL', 'oops'], 'x', { chunkSize: 2 });
26
- expect(result).toStrictEqual([undefined, undefined]);
27
- });
28
-
29
- it('retries only failed fragments', async () => {
30
- let call = 0;
31
- listMap.mockImplementation(async (items) => {
32
- call += 1;
33
- if (call === 1) throw new Error('fail');
34
- return items.map((l) => l.toUpperCase());
35
- });
36
-
37
- const result = await bulkMapRetry(['alpha', 'beta'], 'upper', {
38
- chunkSize: 2,
39
- maxAttempts: 2,
40
- });
41
- expect(result).toStrictEqual(['ALPHA', 'BETA']);
42
- expect(listMap).toHaveBeenCalledTimes(2);
43
- });
44
- });
@@ -1,12 +0,0 @@
1
- # bulk-reduce
2
-
3
- Reduce long lists by processing them in smaller batches. Each batch is combined
4
- with the accumulated result using `listReduce`.
5
-
6
- ```javascript
7
- import bulkReduce from './index.js';
8
-
9
- const logs = ['step one', 'step two', 'step three'];
10
- const result = await bulkReduce(logs, 'summarize');
11
- // => 'summary of steps'
12
- ```
@@ -1,15 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import bulkReduce from './index.js';
3
- import { longTestTimeout } from '../../constants/common.js';
4
-
5
- describe('bulk-reduce examples', () => {
6
- it(
7
- 'reduces a long list sequentially',
8
- async () => {
9
- const items = ['one', 'two', 'three', 'four'];
10
- const result = await bulkReduce(items, 'concatenate', { chunkSize: 2 });
11
- expect(result).toBeDefined();
12
- },
13
- longTestTimeout
14
- );
15
- });
@@ -1,13 +0,0 @@
1
- import listReduce from '../../verblets/list-reduce/index.js';
2
-
3
- export default async function bulkReduce(list, instructions, config = {}) {
4
- const { chunkSize = 10, initial, llm, ...options } = config;
5
- let acc = initial;
6
- for (let i = 0; i < list.length; i += chunkSize) {
7
- const batch = list.slice(i, i + chunkSize);
8
-
9
- // eslint-disable-next-line no-await-in-loop
10
- acc = await listReduce(acc, batch, instructions, { llm, ...options });
11
- }
12
- return acc;
13
- }
@@ -1,25 +0,0 @@
1
- import { beforeEach, describe, expect, it, vi } from 'vitest';
2
- import bulkReduce from './index.js';
3
- import listReduce from '../../verblets/list-reduce/index.js';
4
-
5
- vi.mock('../../verblets/list-reduce/index.js', () => ({
6
- default: vi.fn(async (acc, list) => [acc, ...list].filter(Boolean).join('-')),
7
- }));
8
-
9
- beforeEach(() => {
10
- vi.clearAllMocks();
11
- });
12
-
13
- describe('bulk-reduce chain', () => {
14
- it('reduces in batches', async () => {
15
- const result = await bulkReduce(['a', 'b', 'c', 'd'], 'join', { chunkSize: 2 });
16
- expect(result).toBe('a-b-c-d');
17
- expect(listReduce).toHaveBeenCalledTimes(2);
18
- });
19
-
20
- it('uses initial value', async () => {
21
- const result = await bulkReduce(['x', 'y'], 'join', { initial: '0', chunkSize: 2 });
22
- expect(result).toBe('0-x-y');
23
- expect(listReduce).toHaveBeenCalledTimes(1);
24
- });
25
- });
@@ -1,16 +0,0 @@
1
- # bulk-score
2
-
3
- Score lines of text on a 0–10 scale with automatic calibration. Each batch returns a JSON array so parsing stays reliable even with long lists. The chain first scores everything, then rescors a few low, middle, and high examples to calibrate. Those references feed a second scoring pass so every item is ranked consistently using OpenAI's JSON schema enforcement.
4
-
5
- ```javascript
6
- import bulkScore from './index.js';
7
-
8
- const slogans = [
9
- 'Amazing deals every day!',
10
- 'Unlock a world of wonder',
11
- 'Buy stuff now',
12
- ];
13
-
14
- const { scores } = await bulkScore(slogans, 'How catchy is this marketing slogan?');
15
- // scores like [6, 9, 2]
16
- ```
@@ -1,18 +0,0 @@
1
- {
2
- "$schema": "http://json-schema.org/draft-07/schema#",
3
- "type": "object",
4
- "properties": {
5
- "scores": {
6
- "type": "array",
7
- "description": "Array of numeric scores corresponding to input items",
8
- "items": {
9
- "type": "number",
10
- "minimum": 0,
11
- "maximum": 10,
12
- "description": "Score from 0 (worst) to 10 (best)"
13
- }
14
- }
15
- },
16
- "required": ["scores"],
17
- "additionalProperties": false
18
- }
@@ -1,22 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { longTestTimeout } from '../../constants/common.js';
3
- import bulkScore from './index.js';
4
-
5
- describe('bulkScore examples', () => {
6
- it(
7
- 'ranks jokes by humor',
8
- async () => {
9
- const jokes = [
10
- 'Why did the chicken cross the road? To get to the other side!',
11
- "Parallel lines have so much in common. It's a shame they'll never meet.",
12
- "I told my computer I needed a break, and it said 'I'll go to sleep.'",
13
- ];
14
-
15
- const { scores } = await bulkScore(jokes, 'How funny is this joke?');
16
-
17
- expect(scores).toHaveLength(jokes.length);
18
- scores.forEach((s) => expect(typeof s).toBe('number'));
19
- },
20
- longTestTimeout
21
- );
22
- });
@@ -1,133 +0,0 @@
1
- import fs from 'node:fs/promises';
2
- import path from 'node:path';
3
- import { fileURLToPath } from 'node:url';
4
- import chatGPT from '../../lib/chatgpt/index.js';
5
- import wrapVariable from '../../prompts/wrap-variable.js';
6
- import { constants as promptConstants } from '../../prompts/index.js';
7
-
8
- const { onlyJSONArray } = promptConstants;
9
-
10
- // Get the directory of this module
11
- const __filename = fileURLToPath(import.meta.url);
12
- const __dirname = path.dirname(__filename);
13
-
14
- /**
15
- * Load the JSON schema for bulk score results
16
- * @returns {Promise<Object>} JSON schema for validation
17
- */
18
- async function getBulkScoreSchema() {
19
- const schemaPath = path.join(__dirname, 'bulk-score-result.json');
20
- return JSON.parse(await fs.readFile(schemaPath, 'utf8'));
21
- }
22
-
23
- /**
24
- * Create model options for structured outputs
25
- * @param {string|Object} llm - LLM model name or configuration object
26
- * @returns {Promise<Object>} Model options for chatGPT
27
- */
28
- async function createModelOptions(llm = 'fastGoodCheap') {
29
- const schema = await getBulkScoreSchema();
30
-
31
- const responseFormat = {
32
- type: 'json_schema',
33
- json_schema: {
34
- name: 'bulk_score_result',
35
- schema,
36
- },
37
- };
38
-
39
- if (typeof llm === 'string') {
40
- return {
41
- modelName: llm,
42
- response_format: responseFormat,
43
- };
44
- } else {
45
- return {
46
- ...llm,
47
- response_format: responseFormat,
48
- };
49
- }
50
- }
51
-
52
- async function scoreBatch(items, instructions, reference = [], config = {}) {
53
- const { llm, ...options } = config;
54
- const listBlock = wrapVariable(items.join('\n'), { tag: 'items' });
55
- const refBlock = reference.length
56
- ? `\nCalibration examples (score - text):\n${wrapVariable(
57
- reference.map((r) => `${r.score} - ${r.item}`).join('\n'),
58
- { tag: 'reference' }
59
- )}`
60
- : '';
61
-
62
- const prompt =
63
- `Score each line in <items> from 0 (worst) to 10 (best) based on: ${instructions}.` +
64
- `\nRespond with a JSON object containing a "scores" array of numbers in the same order.` +
65
- `${refBlock}\n${onlyJSONArray}\n${listBlock}`;
66
-
67
- const modelOptions = await createModelOptions(llm);
68
- const response = await chatGPT(prompt, {
69
- modelOptions,
70
- ...options,
71
- });
72
-
73
- // With structured outputs, response should already be parsed and validated
74
- const parsed = typeof response === 'string' ? JSON.parse(response) : response;
75
- // Extract scores from the object structure
76
- const arr = parsed?.scores || parsed;
77
-
78
- if (!Array.isArray(arr) || arr.length !== items.length) {
79
- throw new Error('Score batch mismatch');
80
- }
81
- return arr.map((n) => Number(n));
82
- }
83
-
84
- export default async function bulkScore(list, instructions, config = {}) {
85
- const { chunkSize = 10, examples, llm, ...options } = config;
86
- if (!Array.isArray(list) || list.length === 0) {
87
- return { scores: [], reference: [] };
88
- }
89
-
90
- const firstScores = [];
91
- for (let i = 0; i < list.length; i += chunkSize) {
92
- // eslint-disable-next-line no-await-in-loop
93
- const scores = await scoreBatch(list.slice(i, i + chunkSize), instructions, [], {
94
- llm,
95
- ...options,
96
- });
97
- firstScores.push(...scores);
98
- }
99
-
100
- const scored = list.map((item, idx) => ({ item, score: firstScores[idx] }));
101
-
102
- let reference = examples;
103
- if (!reference) {
104
- const valid = scored.filter((s) => Number.isFinite(s.score));
105
- if (valid.length) {
106
- valid.sort((a, b) => a.score - b.score);
107
- const lows = valid.slice(0, 3);
108
- const highs = valid.slice(-3);
109
- const midStart = Math.max(0, Math.floor(valid.length / 2) - 1);
110
- const mids = valid.slice(midStart, midStart + 3);
111
- reference = [...lows, ...mids, ...highs];
112
- const refItems = reference.map((r) => r.item);
113
- const rescored = await scoreBatch(refItems, instructions, [], { llm, ...options });
114
- rescored.forEach((score, idx) => {
115
- reference[idx].score = score;
116
- });
117
- } else {
118
- reference = [];
119
- }
120
- }
121
-
122
- const finalScores = [];
123
- for (let i = 0; i < list.length; i += chunkSize) {
124
- // eslint-disable-next-line no-await-in-loop
125
- const scores = await scoreBatch(list.slice(i, i + chunkSize), instructions, reference, {
126
- llm,
127
- ...options,
128
- });
129
- finalScores.push(...scores);
130
- }
131
-
132
- return { scores: finalScores, reference };
133
- }
@@ -1,30 +0,0 @@
1
- import { beforeEach, describe, expect, it, vi } from 'vitest';
2
- import bulkScore from './index.js';
3
- import chatGPT from '../../lib/chatgpt/index.js';
4
-
5
- vi.mock('../../lib/chatgpt/index.js', () => ({
6
- default: vi.fn(),
7
- }));
8
-
9
- beforeEach(() => {
10
- vi.clearAllMocks();
11
- });
12
-
13
- describe('bulkScore chain', () => {
14
- it('scores items using two passes', async () => {
15
- chatGPT
16
- .mockResolvedValueOnce('[1,2,3]')
17
- .mockResolvedValueOnce('[1,2,3,4,5,6,7,8,9]')
18
- .mockResolvedValueOnce('[1,2,3]');
19
- const { scores, reference } = await bulkScore(['a', 'bb', 'ccc'], 'length');
20
- expect(scores).toStrictEqual([1, 2, 3]);
21
- expect(reference.length).toBeGreaterThan(0);
22
- expect(chatGPT).toHaveBeenCalled();
23
- });
24
-
25
- it('uses provided examples', async () => {
26
- chatGPT.mockResolvedValueOnce('[1]').mockResolvedValueOnce('[1]');
27
- const { scores } = await bulkScore(['x'], 'length', { examples: [{ item: 'y', score: 2 }] });
28
- expect(scores[0]).toBe(1);
29
- });
30
- });
@@ -1,61 +0,0 @@
1
- # Category Samples Chain
2
-
3
- Generate diverse, representative examples for any category. This chain applies prototype theory and related cognitive science principles to output a well-rounded set of sample items.
4
-
5
- ## Features
6
-
7
- - **Cognitive Science Foundation**: Uses prototype theory and family resemblance principles
8
- - **Diversity Control**: Configurable diversity levels (focused, balanced, high)
9
- - **Context Awareness**: Supports contextual constraints for targeted generation
10
- - **Robust Retry Logic**: Built-in retry mechanisms for reliable generation
11
- - **Scalable Architecture**: Leverages the list chain infrastructure for efficient processing
12
-
13
- ## Usage
14
-
15
- ### Basic Usage
16
-
17
- ```javascript
18
- import categorySamples from './src/chains/category-samples/index.js';
19
-
20
- // Generate basic fruit samples
21
- const fruitSamples = await categorySamples('fruit', {
22
- count: 5,
23
- diversityLevel: 'balanced'
24
- });
25
- // Result: ['apple', 'orange', 'durian', 'banana', 'kiwi']
26
- ```
27
-
28
- ### With Context
29
-
30
- ```javascript
31
- // Generate contextually relevant samples
32
- const birdSamples = await categorySamples('bird', {
33
- context: 'Common backyard birds in North America',
34
- count: 4,
35
- diversityLevel: 'focused'
36
- });
37
- // Result: ['robin', 'cardinal', 'blue jay', 'sparrow']
38
- ```
39
-
40
- ### High Diversity Generation
41
-
42
- ```javascript
43
- // Generate diverse vehicle types
44
- const vehicleSamples = await categorySamples('vehicle', {
45
- count: 6,
46
- diversityLevel: 'high'
47
- });
48
- // Result: ['car', 'bicycle', 'helicopter', 'submarine', 'skateboard', 'spaceship']
49
- ```
50
-
51
- ## API Reference
52
-
53
- ### `categorySamples(categoryName, options)`
54
-
55
- Returns an array of sample items for the given category. Options let you control diversity, add context, and configure retry logic.
56
-
57
- **Common Options**
58
-
59
- - `count` (number): How many samples to return (default: 10)
60
- - `context` (string): Extra context to guide generation
61
- - `diversityLevel` ('focused' | 'balanced' | 'high'): Adjusts how typical or atypical the samples are
@@ -1,103 +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 categorySamples from './index.js';
5
-
6
- describe('Category Samples Chain', () => {
7
- it(
8
- 'generates basic seed items for a category',
9
- async () => {
10
- const seeds = await categorySamples('fruit', {
11
- count: 5,
12
- diversityLevel: 'balanced',
13
- });
14
-
15
- expect(seeds).toHaveLength(5);
16
- expect(seeds.every((seed) => typeof seed === 'string')).toBe(true);
17
- expect(seeds.every((seed) => seed.length > 0)).toBe(true);
18
-
19
- // Use expect-chain for loose verification
20
- const [isValidFruitList] = await aiExpect(
21
- seeds,
22
- undefined,
23
- 'Are these reasonable fruit names that represent a balanced mix of typical and moderately typical fruits?'
24
- );
25
- expect(isValidFruitList).toBe(true);
26
- },
27
- longTestTimeout
28
- );
29
-
30
- it(
31
- 'generates seeds with context',
32
- async () => {
33
- const seeds = await categorySamples('bird', {
34
- context: 'Common backyard birds in North America',
35
- count: 4,
36
- diversityLevel: 'focused',
37
- });
38
-
39
- expect(seeds).toHaveLength(4);
40
- expect(seeds.every((seed) => typeof seed === 'string')).toBe(true);
41
-
42
- // Use expect-chain for loose verification
43
- const [isValidBirdList] = await aiExpect(
44
- seeds,
45
- undefined,
46
- 'Are these reasonable names of common backyard birds that would be found in North America?'
47
- );
48
- expect(isValidBirdList).toBe(true);
49
- },
50
- longTestTimeout
51
- );
52
-
53
- it(
54
- 'generates diverse seeds with high diversity level',
55
- async () => {
56
- const seeds = await categorySamples('vehicle', {
57
- count: 6,
58
- diversityLevel: 'high',
59
- });
60
-
61
- expect(seeds).toHaveLength(6);
62
- expect(seeds.every((seed) => typeof seed === 'string')).toBe(true);
63
-
64
- // Use expect-chain for loose verification - check for diversity without being overly specific
65
- const [isValidVehicleList] = await aiExpect(
66
- seeds,
67
- undefined,
68
- 'Are these vehicle names reasonably diverse, showing variety in the types of vehicles represented?'
69
- );
70
- expect(isValidVehicleList).toBe(true);
71
- },
72
- longTestTimeout
73
- );
74
-
75
- it('throws error for invalid category name', async () => {
76
- await expect(categorySamples('')).rejects.toThrow('categoryName must be a non-empty string');
77
- await expect(categorySamples(null)).rejects.toThrow('categoryName must be a non-empty string');
78
- });
79
-
80
- it(
81
- 'handles retry logic on failures',
82
- async () => {
83
- // This test ensures the retry mechanism works
84
- const seeds = await categorySamples('animal', {
85
- count: 3,
86
- maxRetries: 2,
87
- retryDelay: 100,
88
- });
89
-
90
- expect(seeds).toHaveLength(3);
91
- expect(seeds.every((seed) => typeof seed === 'string')).toBe(true);
92
-
93
- // Use expect-chain for loose verification
94
- const [isValidAnimalList] = await aiExpect(
95
- seeds,
96
- undefined,
97
- 'Are these reasonable animal names?'
98
- );
99
- expect(isValidAnimalList).toBe(true);
100
- },
101
- longTestTimeout
102
- );
103
- });