@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,60 +0,0 @@
1
- import { describe, it, expect, vi } from 'vitest';
2
- import intersection from './index.js';
3
-
4
- vi.mock('../../lib/chatgpt/index.js', () => ({
5
- default: vi.fn(async (prompt) => {
6
- console.log('Mock received prompt:', prompt);
7
- // Look for quoted items in the prompt
8
- const match = prompt.match(/"([^"]+)"/);
9
- if (match) {
10
- const itemsLine = match[1];
11
- const items = itemsLine.split(' | ');
12
- const commonalities = items.map((item) => `common: ${item}`);
13
- // Add combinations
14
- for (let i = 0; i < items.length; i++) {
15
- for (let j = i + 1; j < items.length; j++) {
16
- commonalities.push(`common: ${items[i]} | ${items[j]}`);
17
- }
18
- }
19
- // Add all items combination
20
- if (items.length > 2) {
21
- commonalities.push(`common: ${items.join(' | ')}`);
22
- }
23
- console.log('Mock returning:', JSON.stringify(commonalities));
24
- return JSON.stringify(commonalities);
25
- }
26
- console.log('Mock: no match found, returning empty array');
27
- return JSON.stringify([]);
28
- }),
29
- }));
30
-
31
- describe('intersection verblet', () => {
32
- it('describes commonalities between sets', async () => {
33
- const result = await intersection(['a', 'b', 'c']);
34
- expect(result).toStrictEqual([
35
- 'common: a',
36
- 'common: b',
37
- 'common: c',
38
- 'common: a | b',
39
- 'common: a | c',
40
- 'common: b | c',
41
- 'common: a | b | c',
42
- ]);
43
- });
44
-
45
- it('includes custom instructions in the prompt', async () => {
46
- const chatGPT = (await import('../../lib/chatgpt/index.js')).default;
47
- await intersection(['x', 'y', 'z'], { instructions: 'focus on features' });
48
- expect(chatGPT).toHaveBeenCalledWith(
49
- expect.stringContaining('focus on features'),
50
- expect.any(Object)
51
- );
52
- });
53
-
54
- it('returns empty array when model returns empty response', async () => {
55
- const chatGPT = (await import('../../lib/chatgpt/index.js')).default;
56
- chatGPT.mockResolvedValueOnce('[]');
57
- const result = await intersection(['x', 'y']);
58
- expect(result).toStrictEqual([]);
59
- });
60
- });
@@ -1,16 +0,0 @@
1
- {
2
- "$schema": "http://json-schema.org/draft-07/schema#",
3
- "type": "object",
4
- "properties": {
5
- "items": {
6
- "type": "array",
7
- "description": "Array of common features, instances, or relational links shared by all items",
8
- "items": {
9
- "type": "string",
10
- "description": "A common feature, instance, or relational link"
11
- }
12
- }
13
- },
14
- "required": ["items"],
15
- "additionalProperties": false
16
- }
@@ -1,10 +0,0 @@
1
- # list-expand
2
-
3
- Generate additional items that fit naturally with the given list. The function sends the provided items to ChatGPT and requests more entries of the same kind, returning the expanded list.
4
-
5
- ```javascript
6
- import listExpand from './index.js';
7
-
8
- await listExpand(['red', 'green'], 5);
9
- // => ['red', 'green', 'blue', 'yellow', 'purple']
10
- ```
@@ -1,14 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import listExpand from './index.js';
3
- import { longTestTimeout } from '../../constants/common.js';
4
-
5
- describe('list-expand examples', () => {
6
- it(
7
- 'expands a short list of fruits',
8
- async () => {
9
- const result = await listExpand(['apple', 'banana'], 5);
10
- expect(result.length).toBeGreaterThanOrEqual(5);
11
- },
12
- longTestTimeout
13
- );
14
- });
@@ -1,104 +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
-
7
- // Get the directory of this module
8
- const __filename = fileURLToPath(import.meta.url);
9
- const __dirname = path.dirname(__filename);
10
-
11
- /**
12
- * Load the JSON schema for list expand results
13
- * @returns {Promise<Object>} JSON schema for validation
14
- */
15
- async function getListExpandSchema() {
16
- const schemaPath = path.join(__dirname, 'list-expand-result.json');
17
- return JSON.parse(await fs.readFile(schemaPath, 'utf8'));
18
- }
19
-
20
- /**
21
- * Create model options for structured outputs
22
- * @param {string|Object} llm - LLM model name or configuration object
23
- * @returns {Promise<Object>} Model options for chatGPT
24
- */
25
- async function createModelOptions(llm = 'fastGoodCheap') {
26
- const schema = await getListExpandSchema();
27
-
28
- const responseFormat = {
29
- type: 'json_schema',
30
- json_schema: {
31
- name: 'list_expand_result',
32
- schema,
33
- },
34
- };
35
-
36
- if (typeof llm === 'string') {
37
- return {
38
- modelName: llm,
39
- response_format: responseFormat,
40
- };
41
- } else {
42
- return {
43
- ...llm,
44
- response_format: responseFormat,
45
- };
46
- }
47
- }
48
-
49
- // TODO: This could potentially be refactored to use the list chain (../../chains/list/index.js)
50
- // for better consistency, but would require adapting the list chain to support this simpler
51
- // expansion use case without changing the current behavior and test expectations.
52
-
53
- const buildPrompt = function (list, count) {
54
- const listBlock = wrapVariable(list.join('\n'), { tag: 'list' });
55
- return (
56
- `Expand <list> with new items that belong to the same category and ` +
57
- `match the style of the existing entries. Avoid duplicates or extraneous ` +
58
- `text. Continue adding entries until there are at least ${count} in total. ` +
59
- `Return a JSON object with an "items" array containing all the expanded items.\n\n${listBlock}`
60
- );
61
- };
62
-
63
- /**
64
- * Expand a list with new items that belong to the same category and match the style.
65
- * This is a simplified interface to the list chain for expansion use cases.
66
- *
67
- * @param {string[]} existingList - The list to expand
68
- * @param {number} targetCount - Target total count (default: double the input)
69
- * @param {Object} config - Configuration options including llm settings
70
- * @returns {Promise<string[]>} Expanded list
71
- */
72
- export default async function listExpand(list, count = list.length * 2, config = {}) {
73
- const { llm, ...options } = config;
74
- const modelOptions = await createModelOptions(llm);
75
- const output = await chatGPT(buildPrompt(list, count), { modelOptions, ...options });
76
-
77
- // With structured outputs, response should already be parsed and validated
78
- let parsed;
79
- if (typeof output === 'string') {
80
- try {
81
- parsed = JSON.parse(output);
82
- } catch {
83
- // Handle non-JSON responses (e.g., from mocks or fallback cases)
84
- // Split by newlines and filter out empty lines
85
- const lines = output
86
- .split('\n')
87
- .map((line) => line.trim())
88
- .filter((line) => line.length > 0);
89
- parsed = { items: lines };
90
- }
91
- } else {
92
- parsed = output;
93
- }
94
-
95
- // Extract items from the object structure
96
- const items = parsed?.items || parsed;
97
-
98
- if (!Array.isArray(items)) {
99
- console.warn('Expected items array, got:', typeof items);
100
- return [];
101
- }
102
-
103
- return items;
104
- }
@@ -1,18 +0,0 @@
1
- import { describe, expect, it, vi } from 'vitest';
2
- import listExpand from './index.js';
3
-
4
- vi.mock('../../lib/chatgpt/index.js', () => ({
5
- default: vi.fn(async (prompt) => {
6
- const match = prompt.match(/<list>\n([\s\S]*?)\n<\/list>/);
7
- const lines = match ? match[1].split('\n') : [];
8
- const extras = lines.map((l) => `${l}-extra`);
9
- return [...lines, ...extras].join('\n');
10
- }),
11
- }));
12
-
13
- describe('list-expand verblet', () => {
14
- it('expands items to at least the requested count', async () => {
15
- const result = await listExpand(['alpha', 'beta'], 4);
16
- expect(result).toStrictEqual(['alpha', 'beta', 'alpha-extra', 'beta-extra']);
17
- });
18
- });
@@ -1,16 +0,0 @@
1
- {
2
- "$schema": "http://json-schema.org/draft-07/schema#",
3
- "type": "object",
4
- "properties": {
5
- "items": {
6
- "type": "array",
7
- "description": "Array of expanded list items",
8
- "items": {
9
- "type": "string",
10
- "description": "A list item that belongs to the same category and matches the style"
11
- }
12
- }
13
- },
14
- "required": ["items"],
15
- "additionalProperties": false
16
- }
@@ -1,22 +0,0 @@
1
- # list-filter
2
-
3
- Filter a list with a single ChatGPT call using custom instructions.
4
-
5
- ```javascript
6
- import listFilter from './index.js';
7
-
8
- const reflections = [
9
- 'Losing that match taught me the value of persistence.',
10
- "I hate losing and it proves I'm worthless.",
11
- 'After failing my exam, I studied harder and passed the retake.',
12
- "No matter what I do, I'll never succeed.",
13
- ];
14
- const growth = await listFilter(
15
- reflections,
16
- 'keep only reflections that show personal growth or learning from mistakes'
17
- );
18
- // => [
19
- // 'Losing that match taught me the value of persistence.',
20
- // 'After failing my exam, I studied harder and passed the retake.',
21
- // ]
22
- ```
@@ -1,26 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import listFilter from './index.js';
3
- import { longTestTimeout } from '../../constants/common.js';
4
-
5
- describe('list-filter examples', () => {
6
- it(
7
- 'filters items with custom instructions',
8
- async () => {
9
- const entries = [
10
- 'Losing that match taught me the value of persistence.',
11
- "I hate losing and it proves I'm worthless.",
12
- 'After failing my exam, I studied harder and passed the retake.',
13
- "No matter what I do, I'll never succeed.",
14
- ];
15
- const result = await listFilter(
16
- entries,
17
- 'keep only reflections that show personal growth or learning from mistakes'
18
- );
19
- expect(result).toStrictEqual([
20
- 'Losing that match taught me the value of persistence.',
21
- 'After failing my exam, I studied harder and passed the retake.',
22
- ]);
23
- },
24
- longTestTimeout
25
- );
26
- });
@@ -1,18 +0,0 @@
1
- import chatGPT from '../../lib/chatgpt/index.js';
2
- import wrapVariable from '../../prompts/wrap-variable.js';
3
-
4
- function buildPrompt(list, instructions) {
5
- const instructionsBlock = wrapVariable(instructions, { tag: 'instructions' });
6
- const listBlock = wrapVariable(list.join('\n'), { tag: 'list' });
7
- return `From the <list>, select only the items that satisfy the <instructions>. Return one item per line without numbering. If none match, return an empty string.\n\n${instructionsBlock}\n${listBlock}`;
8
- }
9
-
10
- export default async function listFilter(list, instructions, config = {}) {
11
- const { llm, ...options } = config;
12
- const output = await chatGPT(buildPrompt(list, instructions), {
13
- modelOptions: { ...llm },
14
- ...options,
15
- });
16
- const trimmed = output.trim();
17
- return trimmed ? trimmed.split('\n') : [];
18
- }
@@ -1,19 +0,0 @@
1
- import { describe, expect, it, vi } from 'vitest';
2
- import listFilter from './index.js';
3
-
4
- vi.mock('../../lib/chatgpt/index.js', () => ({
5
- default: vi.fn(async (prompt) => {
6
- const listMatch = prompt.match(/<list>\n([\s\S]*?)\n<\/list>/);
7
- const lines = listMatch ? listMatch[1].split('\n') : [];
8
- const instMatch = prompt.match(/"([^"]+)"/);
9
- const letter = instMatch ? instMatch[1] : '';
10
- return lines.filter((l) => l.includes(letter)).join('\n');
11
- }),
12
- }));
13
-
14
- describe('list-filter verblet', () => {
15
- it('filters items using instructions', async () => {
16
- const result = await listFilter(['alpha', 'beta', 'gamma'], 'm');
17
- expect(result).toStrictEqual(['gamma']);
18
- });
19
- });
@@ -1,11 +0,0 @@
1
- # list-find
2
-
3
- Find the single best match in a list using natural language instructions.
4
-
5
- ```javascript
6
- import listFind from './index.js';
7
-
8
- const snacks = ['apple pie', 'fruit roll-up', 'carrot sticks'];
9
- await listFind(snacks, 'which snack feels most nostalgic for kids of the 90s?');
10
- // => 'fruit roll-up'
11
- ```
@@ -1,15 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import listFind from './index.js';
3
- import { longTestTimeout } from '../../constants/common.js';
4
-
5
- describe('list-find examples', () => {
6
- it(
7
- 'finds the item that best fits the instructions',
8
- async () => {
9
- const books = ['space adventure', 'medieval romance', 'futuristic mystery'];
10
- const result = await listFind(books, 'which book sounds most futuristic?');
11
- expect(result).toBeDefined();
12
- },
13
- longTestTimeout
14
- );
15
- });
@@ -1,17 +0,0 @@
1
- import chatGPT from '../../lib/chatgpt/index.js';
2
- import wrapVariable from '../../prompts/wrap-variable.js';
3
-
4
- const buildPrompt = (list, instructions) => {
5
- const instructionsBlock = wrapVariable(instructions, { tag: 'instructions' });
6
- const listBlock = wrapVariable(list.join('\n'), { tag: 'list' });
7
- return `From the <list>, select the single item that best satisfies the <instructions>. If none apply, return an empty string.\n\n${instructionsBlock}\n${listBlock}`;
8
- };
9
-
10
- export default async function listFind(list, instructions, config = {}) {
11
- const { llm, ...options } = config;
12
- const output = await chatGPT(buildPrompt(list, instructions), {
13
- modelOptions: { ...llm },
14
- ...options,
15
- });
16
- return output.trim();
17
- }
@@ -1,19 +0,0 @@
1
- import { describe, expect, it, vi } from 'vitest';
2
- import listFind from './index.js';
3
-
4
- vi.mock('../../lib/chatgpt/index.js', () => ({
5
- default: vi.fn(async (prompt) => {
6
- const listMatch = prompt.match(/<list>\n([\s\S]*?)\n<\/list>/);
7
- const lines = listMatch ? listMatch[1].split('\n') : [];
8
- const parts = prompt.split('"');
9
- const letter = [...parts].reverse().find((p) => /^[a-z]+$/i.test(p.trim())) || '';
10
- return lines.find((l) => l.includes(letter)) || '';
11
- }),
12
- }));
13
-
14
- describe('list-find verblet', () => {
15
- it('finds item using instructions', async () => {
16
- const result = await listFind(['alpha', 'beta', 'gamma'], 'find "b"');
17
- expect(result).toBe('beta');
18
- });
19
- });
@@ -1,16 +0,0 @@
1
- # list-group
2
-
3
- Group a list into stable groups using custom instructions. Optionally
4
- provide a list of categories to maintain consistency across runs.
5
-
6
- ```javascript
7
- import listGroup from './index.js';
8
-
9
- const categories = ['fruit', 'vegetable'];
10
- await listGroup(
11
- ['apple', 'banana', 'carrot'],
12
- 'Classify each item',
13
- categories
14
- );
15
- // => { fruit: ['apple', 'banana'], vegetable: ['carrot'] }
16
- ```
@@ -1,16 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import listGroup from './index.js';
3
- import { longTestTimeout } from '../../constants/common.js';
4
-
5
- describe('list-group examples', () => {
6
- it(
7
- 'groups a list into categories',
8
- async () => {
9
- const items = ['apple', 'beer', 'orange', 'wine', 'banana'];
10
- const result = await listGroup(items, 'Group as drinks or food', ['drink', 'food']);
11
- expect(typeof result).toBe('object');
12
- expect(Object.keys(result).length).toBeGreaterThan(0);
13
- },
14
- longTestTimeout
15
- );
16
- });
@@ -1,112 +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
-
7
- // Get the directory of this module
8
- const __filename = fileURLToPath(import.meta.url);
9
- const __dirname = path.dirname(__filename);
10
-
11
- /**
12
- * Load the JSON schema for list group results
13
- * @returns {Promise<Object>} JSON schema for validation
14
- */
15
- async function getListGroupSchema() {
16
- const schemaPath = path.join(__dirname, 'list-group-result.json');
17
- return JSON.parse(await fs.readFile(schemaPath, 'utf8'));
18
- }
19
-
20
- /**
21
- * Create model options for structured outputs
22
- * @param {string|Object} llm - LLM model name or configuration object
23
- * @returns {Promise<Object>} Model options for chatGPT
24
- */
25
- async function createModelOptions(llm = 'fastGoodCheap') {
26
- const schema = await getListGroupSchema();
27
-
28
- const responseFormat = {
29
- type: 'json_schema',
30
- json_schema: {
31
- name: 'list_group_result',
32
- schema,
33
- },
34
- };
35
-
36
- if (typeof llm === 'string') {
37
- return {
38
- modelName: llm,
39
- response_format: responseFormat,
40
- };
41
- } else {
42
- return {
43
- ...llm,
44
- response_format: responseFormat,
45
- };
46
- }
47
- }
48
-
49
- const buildPrompt = (list, instructions, categories) => {
50
- const instructionsBlock = wrapVariable(instructions, { tag: 'instructions' });
51
- const listBlock = wrapVariable(list.join('\n'), { tag: 'list' });
52
- const categoryBlock =
53
- categories && categories.length
54
- ? `${wrapVariable(categories.join('\n'), { tag: 'categories' })}\n`
55
- : '';
56
- const categoryText = categories && categories.length ? 'one of the <categories>' : 'a group';
57
-
58
- return `Assign each line in <list> to ${categoryText} according to <instructions>.
59
-
60
- Return a JSON object with a "labels" array containing exactly ${list.length} group names, one for each item in the same order as the input list.
61
-
62
- ${instructionsBlock}
63
- ${categoryBlock}${listBlock}
64
-
65
- Output format: {"labels": [array with exactly ${list.length} group names]}`;
66
- };
67
-
68
- export default async function listGroup(list, instructions, categories, config = {}) {
69
- const { llm, ...options } = config;
70
- const modelOptions = await createModelOptions(llm);
71
- const output = await chatGPT(buildPrompt(list, instructions, categories), {
72
- modelOptions,
73
- ...options,
74
- });
75
-
76
- // With structured outputs, response should already be parsed and validated
77
- let parsed;
78
- if (typeof output === 'string') {
79
- try {
80
- parsed = JSON.parse(output);
81
- } catch {
82
- // Handle non-JSON responses (e.g., from mocks or fallback cases)
83
- // Split by newlines and filter out empty lines
84
- const lines = output
85
- .split('\n')
86
- .map((line) => line.trim())
87
- .filter((line) => line.length > 0);
88
- parsed = { labels: lines };
89
- }
90
- } else {
91
- parsed = output;
92
- }
93
-
94
- // Extract labels from the object structure
95
- const labels = parsed?.labels || parsed;
96
-
97
- if (!Array.isArray(labels) || labels.length !== list.length) {
98
- console.warn(`Expected ${list.length} labels, got ${labels?.length || 0}`);
99
- // Fallback to default labels if parsing fails
100
- return { other: [...list] };
101
- }
102
-
103
- // Group items by their labels
104
- const result = {};
105
- labels.forEach((label, idx) => {
106
- const key = String(label).trim() || 'other';
107
- if (!result[key]) result[key] = [];
108
- result[key].push(list[idx]);
109
- });
110
-
111
- return result;
112
- }
@@ -1,35 +0,0 @@
1
- import listGroup from './index.js';
2
- import { vi, describe, it, expect } from 'vitest';
3
-
4
- vi.mock('../../lib/chatgpt/index.js', () => ({
5
- default: vi.fn(() => 'odd\neven\nodd'),
6
- }));
7
-
8
- const examples = [
9
- {
10
- inputs: {
11
- list: ['a', 'bb', 'ccc'],
12
- instructions: 'odd or even length',
13
- categories: ['odd', 'even'],
14
- },
15
- want: { result: { odd: ['a', 'ccc'], even: ['bb'] } },
16
- },
17
- ];
18
-
19
- describe('list-group verblet', () => {
20
- it('groups items using instructions', async () => {
21
- const result = await listGroup(['a', 'bb', 'ccc'], 'odd or even length', ['odd', 'even']);
22
- expect(result).toStrictEqual({ odd: ['a', 'ccc'], even: ['bb'] });
23
- });
24
-
25
- examples.forEach((example) => {
26
- it(example.inputs.instructions, async () => {
27
- const result = await listGroup(
28
- example.inputs.list,
29
- example.inputs.instructions,
30
- example.inputs.categories
31
- );
32
- expect(result).toStrictEqual(example.want.result);
33
- });
34
- });
35
- });
@@ -1,16 +0,0 @@
1
- {
2
- "$schema": "http://json-schema.org/draft-07/schema#",
3
- "type": "object",
4
- "properties": {
5
- "labels": {
6
- "type": "array",
7
- "description": "Array of group labels corresponding to input items in the same order",
8
- "items": {
9
- "type": "string",
10
- "description": "Group label for the corresponding item"
11
- }
12
- }
13
- },
14
- "required": ["labels"],
15
- "additionalProperties": false
16
- }
@@ -1,11 +0,0 @@
1
- # list-map
2
-
3
- Transform a list with a single ChatGPT call by providing mapping instructions.
4
- The function hides the boilerplate prompting so you only supply the instructions.
5
-
6
- ```javascript
7
- import { listMap } from '../../index.js';
8
-
9
- await listMap(['Budget smartphone', 'Luxury watch'], 'Write a short playful tagline');
10
- // => ['Affordable tech for everyone', 'Elegance that tells time']
11
- ```
@@ -1,15 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import listMap from './index.js';
3
- import { longTestTimeout } from '../../constants/common.js';
4
-
5
- describe('list-map examples', () => {
6
- it(
7
- 'maps creative slogans',
8
- async () => {
9
- const items = ['smart toaster', 'robot vacuum'];
10
- const result = await listMap(items, 'Give a playful marketing slogan');
11
- expect(result.length).toBe(2);
12
- },
13
- longTestTimeout
14
- );
15
- });
@@ -1,26 +0,0 @@
1
- import chatGPT from '../../lib/chatgpt/index.js';
2
- import wrapVariable from '../../prompts/wrap-variable.js';
3
-
4
- const buildPrompt = function (list, instructions) {
5
- const instructionsBlock = wrapVariable(instructions, { tag: 'instructions' });
6
- const listBlock = wrapVariable(list.join('\n'), { tag: 'list' });
7
- return `For each line in <list>, apply the <instructions> to transform it.\nReturn the same number of lines without numbering.\n\n${instructionsBlock}\n${listBlock}`;
8
- };
9
-
10
- export default async function listMap(list, instructions, config = {}) {
11
- const { llm, ...options } = config;
12
- const output = await chatGPT(buildPrompt(list, instructions), {
13
- modelOptions: { ...llm },
14
- ...options,
15
- });
16
- const lines = output
17
- .split('\n')
18
- .map((line) => line.trim())
19
- .filter((line) => line.length > 0);
20
- if (lines.length !== list.length) {
21
- throw new Error(
22
- `Batch output line count mismatch (expected ${list.length}, got ${lines.length})`
23
- );
24
- }
25
- return lines;
26
- }