@far-world-labs/verblets 0.1.7 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (306) 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 -8
  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 -8
  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/generate-chain/index.js +0 -111
  21. package/scripts/generate-lib/index.js +0 -68
  22. package/scripts/generate-test/index.js +0 -137
  23. package/scripts/generate-verblet/README.md +0 -17
  24. package/scripts/generate-verblet/index.js +0 -110
  25. package/scripts/run.sh +0 -15
  26. package/scripts/runner/index.js +0 -56
  27. package/scripts/simple-editor/README.md +0 -34
  28. package/scripts/simple-editor/index.js +0 -79
  29. package/scripts/summarize-files/index.js +0 -70
  30. package/src/chains/README.md +0 -30
  31. package/src/chains/anonymize/README.md +0 -21
  32. package/src/chains/anonymize/index.examples.js +0 -75
  33. package/src/chains/anonymize/index.js +0 -121
  34. package/src/chains/anonymize/index.spec.js +0 -78
  35. package/src/chains/bulk-central-tendency/index.examples.js +0 -138
  36. package/src/chains/bulk-central-tendency/index.js +0 -91
  37. package/src/chains/bulk-filter/README.md +0 -21
  38. package/src/chains/bulk-filter/index.examples.js +0 -22
  39. package/src/chains/bulk-filter/index.js +0 -58
  40. package/src/chains/bulk-filter/index.spec.js +0 -38
  41. package/src/chains/bulk-find/README.md +0 -16
  42. package/src/chains/bulk-find/index.examples.js +0 -20
  43. package/src/chains/bulk-find/index.js +0 -30
  44. package/src/chains/bulk-find/index.spec.js +0 -26
  45. package/src/chains/bulk-group/README.md +0 -23
  46. package/src/chains/bulk-group/index.examples.js +0 -18
  47. package/src/chains/bulk-group/index.js +0 -34
  48. package/src/chains/bulk-group/index.spec.js +0 -41
  49. package/src/chains/bulk-map/README.md +0 -43
  50. package/src/chains/bulk-map/index.examples.js +0 -17
  51. package/src/chains/bulk-map/index.js +0 -86
  52. package/src/chains/bulk-map/index.spec.js +0 -44
  53. package/src/chains/bulk-reduce/README.md +0 -12
  54. package/src/chains/bulk-reduce/index.examples.js +0 -15
  55. package/src/chains/bulk-reduce/index.js +0 -13
  56. package/src/chains/bulk-reduce/index.spec.js +0 -25
  57. package/src/chains/bulk-score/README.md +0 -16
  58. package/src/chains/bulk-score/bulk-score-result.json +0 -18
  59. package/src/chains/bulk-score/index.examples.js +0 -22
  60. package/src/chains/bulk-score/index.js +0 -133
  61. package/src/chains/bulk-score/index.spec.js +0 -30
  62. package/src/chains/category-samples/README.md +0 -61
  63. package/src/chains/category-samples/index.examples.js +0 -103
  64. package/src/chains/category-samples/index.js +0 -134
  65. package/src/chains/collect-terms/README.md +0 -12
  66. package/src/chains/collect-terms/index.examples.js +0 -16
  67. package/src/chains/collect-terms/index.js +0 -44
  68. package/src/chains/collect-terms/index.spec.js +0 -25
  69. package/src/chains/date/README.md +0 -12
  70. package/src/chains/date/index.examples.js +0 -47
  71. package/src/chains/date/index.js +0 -74
  72. package/src/chains/date/index.spec.js +0 -62
  73. package/src/chains/disambiguate/README.md +0 -22
  74. package/src/chains/disambiguate/disambiguate-meanings-result.json +0 -16
  75. package/src/chains/disambiguate/index.examples.js +0 -18
  76. package/src/chains/disambiguate/index.js +0 -92
  77. package/src/chains/disambiguate/index.spec.js +0 -25
  78. package/src/chains/dismantle/README.md +0 -67
  79. package/src/chains/dismantle/dismantle.examples.js +0 -27
  80. package/src/chains/dismantle/index.examples.js +0 -30
  81. package/src/chains/dismantle/index.js +0 -303
  82. package/src/chains/dismantle/index.spec.js +0 -32
  83. package/src/chains/expect/README.md +0 -171
  84. package/src/chains/expect/index.examples.js +0 -146
  85. package/src/chains/expect/index.js +0 -173
  86. package/src/chains/expect/index.spec.js +0 -324
  87. package/src/chains/filter-ambiguous/README.md +0 -11
  88. package/src/chains/filter-ambiguous/index.examples.js +0 -20
  89. package/src/chains/filter-ambiguous/index.js +0 -49
  90. package/src/chains/filter-ambiguous/index.spec.js +0 -31
  91. package/src/chains/glossary/README.md +0 -19
  92. package/src/chains/glossary/index.examples.js +0 -386
  93. package/src/chains/glossary/index.js +0 -75
  94. package/src/chains/glossary/index.spec.js +0 -19
  95. package/src/chains/intersections/README.md +0 -152
  96. package/src/chains/intersections/index.examples.js +0 -279
  97. package/src/chains/intersections/index.js +0 -366
  98. package/src/chains/intersections/intersection-result.json +0 -38
  99. package/src/chains/list/index.examples.js +0 -68
  100. package/src/chains/list/index.js +0 -214
  101. package/src/chains/list/index.spec.js +0 -67
  102. package/src/chains/list/list-result.json +0 -16
  103. package/src/chains/list/schema.json +0 -24
  104. package/src/chains/llm-logger/README.md +0 -208
  105. package/src/chains/llm-logger/index.js +0 -205
  106. package/src/chains/llm-logger/index.spec.js +0 -330
  107. package/src/chains/questions/index.examples.js +0 -69
  108. package/src/chains/questions/index.js +0 -135
  109. package/src/chains/questions/index.spec.js +0 -29
  110. package/src/chains/scan-js/index.js +0 -116
  111. package/src/chains/set-interval/README.md +0 -81
  112. package/src/chains/set-interval/index.examples.js +0 -36
  113. package/src/chains/set-interval/index.js +0 -131
  114. package/src/chains/set-interval/index.spec.js +0 -70
  115. package/src/chains/socratic/README.md +0 -17
  116. package/src/chains/socratic/index.js +0 -64
  117. package/src/chains/socratic/index.spec.js +0 -24
  118. package/src/chains/sort/index.examples.js +0 -36
  119. package/src/chains/sort/index.js +0 -163
  120. package/src/chains/sort/index.spec.js +0 -112
  121. package/src/chains/sort/sort-result.json +0 -16
  122. package/src/chains/summary-map/README.md +0 -41
  123. package/src/chains/summary-map/index.examples.js +0 -64
  124. package/src/chains/summary-map/index.js +0 -226
  125. package/src/chains/summary-map/index.spec.js +0 -153
  126. package/src/chains/test/index.js +0 -114
  127. package/src/chains/test-advice/index.js +0 -35
  128. package/src/chains/themes/README.md +0 -20
  129. package/src/chains/themes/index.examples.js +0 -17
  130. package/src/chains/themes/index.js +0 -28
  131. package/src/chains/themes/index.spec.js +0 -19
  132. package/src/chains/veiled-variants/index.examples.js +0 -18
  133. package/src/chains/veiled-variants/index.js +0 -107
  134. package/src/chains/veiled-variants/index.spec.js +0 -40
  135. package/src/constants/common.js +0 -7
  136. package/src/constants/messages.js +0 -3
  137. package/src/constants/models.js +0 -183
  138. package/src/index.js +0 -193
  139. package/src/json-schemas/README.md +0 -13
  140. package/src/json-schemas/cars-test.json +0 -11
  141. package/src/json-schemas/index.js +0 -12
  142. package/src/json-schemas/intent.json +0 -38
  143. package/src/json-schemas/schema-dot-org-photograph.json +0 -133
  144. package/src/json-schemas/schema-dot-org-place.json +0 -129
  145. package/src/lib/README.md +0 -26
  146. package/src/lib/any-signal/index.js +0 -28
  147. package/src/lib/bulk-filter/README.md +0 -22
  148. package/src/lib/bulk-filter/index.examples.js +0 -27
  149. package/src/lib/bulk-filter/index.js +0 -63
  150. package/src/lib/bulk-filter/index.spec.js +0 -38
  151. package/src/lib/bulk-find/README.md +0 -18
  152. package/src/lib/bulk-find/index.examples.js +0 -19
  153. package/src/lib/bulk-find/index.js +0 -30
  154. package/src/lib/bulk-find/index.spec.js +0 -41
  155. package/src/lib/chatgpt/index.js +0 -163
  156. package/src/lib/combinations/index.js +0 -30
  157. package/src/lib/combinations/index.spec.js +0 -23
  158. package/src/lib/editor/index.js +0 -31
  159. package/src/lib/functional/index.js +0 -28
  160. package/src/lib/logger-service/index.js +0 -32
  161. package/src/lib/parse-js-parts/index.js +0 -321
  162. package/src/lib/parse-js-parts/index.spec.js +0 -156
  163. package/src/lib/parse-llm-list/README.md +0 -39
  164. package/src/lib/parse-llm-list/index.js +0 -54
  165. package/src/lib/parse-llm-list/index.spec.js +0 -59
  166. package/src/lib/path-aliases/index.js +0 -37
  167. package/src/lib/path-aliases/index.spec.js +0 -64
  168. package/src/lib/pave/index.js +0 -34
  169. package/src/lib/pave/index.spec.js +0 -76
  170. package/src/lib/prompt-cache/index.js +0 -50
  171. package/src/lib/retry/index.js +0 -66
  172. package/src/lib/retry/index.spec.js +0 -86
  173. package/src/lib/ring-buffer/README.md +0 -460
  174. package/src/lib/ring-buffer/index.js +0 -1074
  175. package/src/lib/search-best-first/city-walk.spec.js +0 -37
  176. package/src/lib/search-best-first/index.js +0 -97
  177. package/src/lib/search-best-first/index.spec.js +0 -35
  178. package/src/lib/search-js-files/code-features-property-definitions.json +0 -123
  179. package/src/lib/search-js-files/index.examples.js +0 -22
  180. package/src/lib/search-js-files/index.js +0 -155
  181. package/src/lib/search-js-files/index.spec.js +0 -34
  182. package/src/lib/search-js-files/scan-file.js +0 -242
  183. package/src/lib/shorten-text/index.js +0 -25
  184. package/src/lib/shorten-text/index.spec.js +0 -68
  185. package/src/lib/strip-numeric/index.js +0 -5
  186. package/src/lib/strip-response/index.js +0 -30
  187. package/src/lib/template-replace/index.js +0 -23
  188. package/src/lib/template-replace/index.spec.js +0 -60
  189. package/src/lib/timed-abort-controller/index.js +0 -41
  190. package/src/lib/to-bool/index.js +0 -8
  191. package/src/lib/to-date/index.js +0 -11
  192. package/src/lib/to-enum/index.js +0 -14
  193. package/src/lib/to-number/index.js +0 -12
  194. package/src/lib/to-number-with-units/index.js +0 -51
  195. package/src/lib/transcribe/index.js +0 -78
  196. package/src/prompts/README.md +0 -17
  197. package/src/prompts/as-enum.js +0 -5
  198. package/src/prompts/as-json-schema.js +0 -9
  199. package/src/prompts/as-object-with-schema.js +0 -26
  200. package/src/prompts/as-schema-org-text.js +0 -25
  201. package/src/prompts/as-schema-org-type.js +0 -1
  202. package/src/prompts/blog-post.js +0 -7
  203. package/src/prompts/code-features.js +0 -24
  204. package/src/prompts/constants.js +0 -101
  205. package/src/prompts/features-json-schema.js +0 -27
  206. package/src/prompts/generate-collection.js +0 -26
  207. package/src/prompts/generate-list.js +0 -48
  208. package/src/prompts/generate-questions.js +0 -19
  209. package/src/prompts/index.js +0 -20
  210. package/src/prompts/intent.js +0 -60
  211. package/src/prompts/output-succinct-names.js +0 -3
  212. package/src/prompts/select-from-threshold.js +0 -17
  213. package/src/prompts/sort.js +0 -31
  214. package/src/prompts/style.js +0 -38
  215. package/src/prompts/summarize.js +0 -13
  216. package/src/prompts/token-budget.js +0 -3
  217. package/src/prompts/wrap-list.js +0 -11
  218. package/src/prompts/wrap-variable.js +0 -36
  219. package/src/services/llm-model/global-overrides.spec.js +0 -432
  220. package/src/services/llm-model/index.js +0 -308
  221. package/src/services/llm-model/model.js +0 -21
  222. package/src/services/llm-model/negotiate.spec.js +0 -447
  223. package/src/services/redis/index.js +0 -147
  224. package/src/test/setup.js +0 -20
  225. package/src/verblets/README.md +0 -26
  226. package/src/verblets/auto/index.examples.js +0 -31
  227. package/src/verblets/auto/index.js +0 -28
  228. package/src/verblets/auto/index.spec.js +0 -32
  229. package/src/verblets/bool/README.md +0 -36
  230. package/src/verblets/bool/index.examples.js +0 -80
  231. package/src/verblets/bool/index.js +0 -25
  232. package/src/verblets/bool/index.schema.json +0 -14
  233. package/src/verblets/bool/index.spec.js +0 -33
  234. package/src/verblets/central-tendency/README.md +0 -166
  235. package/src/verblets/central-tendency/central-tendency-result.json +0 -24
  236. package/src/verblets/central-tendency/index.examples.js +0 -196
  237. package/src/verblets/central-tendency/index.js +0 -171
  238. package/src/verblets/central-tendency/index.spec.js +0 -148
  239. package/src/verblets/enum/index.examples.js +0 -30
  240. package/src/verblets/enum/index.js +0 -18
  241. package/src/verblets/enum/index.spec.js +0 -35
  242. package/src/verblets/expect/README.md +0 -64
  243. package/src/verblets/expect/index.examples.js +0 -109
  244. package/src/verblets/expect/index.js +0 -75
  245. package/src/verblets/expect/index.spec.js +0 -127
  246. package/src/verblets/intent/index.examples.js +0 -139
  247. package/src/verblets/intent/index.js +0 -60
  248. package/src/verblets/intent/index.spec.js +0 -31
  249. package/src/verblets/intersection/README.md +0 -16
  250. package/src/verblets/intersection/index.examples.js +0 -89
  251. package/src/verblets/intersection/index.js +0 -84
  252. package/src/verblets/intersection/index.spec.js +0 -60
  253. package/src/verblets/intersection/intersection-result.json +0 -16
  254. package/src/verblets/list-expand/README.md +0 -10
  255. package/src/verblets/list-expand/index.examples.js +0 -14
  256. package/src/verblets/list-expand/index.js +0 -104
  257. package/src/verblets/list-expand/index.spec.js +0 -18
  258. package/src/verblets/list-expand/list-expand-result.json +0 -16
  259. package/src/verblets/list-filter/README.md +0 -22
  260. package/src/verblets/list-filter/index.examples.js +0 -26
  261. package/src/verblets/list-filter/index.js +0 -18
  262. package/src/verblets/list-filter/index.spec.js +0 -19
  263. package/src/verblets/list-find/README.md +0 -11
  264. package/src/verblets/list-find/index.examples.js +0 -15
  265. package/src/verblets/list-find/index.js +0 -17
  266. package/src/verblets/list-find/index.spec.js +0 -19
  267. package/src/verblets/list-group/README.md +0 -16
  268. package/src/verblets/list-group/index.examples.js +0 -16
  269. package/src/verblets/list-group/index.js +0 -112
  270. package/src/verblets/list-group/index.spec.js +0 -35
  271. package/src/verblets/list-group/list-group-result.json +0 -16
  272. package/src/verblets/list-map/README.md +0 -11
  273. package/src/verblets/list-map/index.examples.js +0 -15
  274. package/src/verblets/list-map/index.js +0 -26
  275. package/src/verblets/list-map/index.spec.js +0 -17
  276. package/src/verblets/list-reduce/README.md +0 -10
  277. package/src/verblets/list-reduce/index.examples.js +0 -14
  278. package/src/verblets/list-reduce/index.js +0 -21
  279. package/src/verblets/list-reduce/index.spec.js +0 -27
  280. package/src/verblets/list-reduce/index.spec.jsx +0 -27
  281. package/src/verblets/name/README.md +0 -15
  282. package/src/verblets/name/index.examples.js +0 -28
  283. package/src/verblets/name/index.js +0 -19
  284. package/src/verblets/name/index.spec.js +0 -33
  285. package/src/verblets/name-similar-to/README.md +0 -26
  286. package/src/verblets/name-similar-to/index.examples.js +0 -18
  287. package/src/verblets/name-similar-to/index.js +0 -20
  288. package/src/verblets/name-similar-to/index.spec.js +0 -13
  289. package/src/verblets/number/index.examples.js +0 -199
  290. package/src/verblets/number/index.js +0 -25
  291. package/src/verblets/number/index.spec.js +0 -33
  292. package/src/verblets/number-with-units/index.examples.js +0 -38
  293. package/src/verblets/number-with-units/index.js +0 -84
  294. package/src/verblets/number-with-units/index.spec.js +0 -46
  295. package/src/verblets/number-with-units/number-with-units-result.json +0 -23
  296. package/src/verblets/schema-org/index.examples.js +0 -51
  297. package/src/verblets/schema-org/index.js +0 -37
  298. package/src/verblets/schema-org/index.spec.js +0 -39
  299. package/src/verblets/sentiment/README.md +0 -10
  300. package/src/verblets/sentiment/index.examples.js +0 -20
  301. package/src/verblets/sentiment/index.js +0 -9
  302. package/src/verblets/sentiment/index.spec.js +0 -20
  303. package/src/verblets/to-object/README.md +0 -38
  304. package/src/verblets/to-object/index.examples.js +0 -29
  305. package/src/verblets/to-object/index.js +0 -131
  306. package/src/verblets/to-object/index.spec.js +0 -71
@@ -1,127 +0,0 @@
1
- import { describe, expect, it, vi } from 'vitest';
2
- import aiExpect from './index.js';
3
- import { longTestTimeout } from '../../constants/common.js';
4
-
5
- // Mock the chatgpt function to avoid actual API calls
6
- vi.mock('../../lib/chatgpt/index.js', () => ({
7
- default: vi.fn().mockImplementation((prompt) => {
8
- // Handle exact equality checks
9
- if (prompt.includes('Does the actual value strictly equal the expected value?')) {
10
- if (prompt.includes('Actual: "hello"') && prompt.includes('Expected: "hello"')) {
11
- return 'True';
12
- }
13
- if (prompt.includes('Actual: "goodbye"') && prompt.includes('Expected: "hello"')) {
14
- return 'False';
15
- }
16
- }
17
-
18
- // Handle constraint-based validations (format: "Given this constraint:")
19
- if (prompt.includes('Given this constraint:')) {
20
- if (prompt.includes('Is this a greeting?') && prompt.includes('Hello world!')) {
21
- return 'True';
22
- }
23
-
24
- if (prompt.includes('Is this text professional and grammatically correct?')) {
25
- if (prompt.includes('well-written, professional email')) {
26
- return 'True';
27
- }
28
- }
29
-
30
- if (prompt.includes('Does this person data look realistic?')) {
31
- if (prompt.includes('John Doe') && prompt.includes('"age": 30')) {
32
- return 'True';
33
- }
34
- }
35
-
36
- if (prompt.includes('Is this recommendation specific and actionable?')) {
37
- if (prompt.includes('Increase marketing budget by 20%')) {
38
- return 'True';
39
- }
40
- }
41
- }
42
-
43
- // Default to False for unmatched cases
44
- return 'False';
45
- }),
46
- }));
47
-
48
- describe('expect verblet', () => {
49
- it(
50
- 'should pass for exact equality',
51
- async () => {
52
- const result = await aiExpect('hello').toEqual('hello', { throws: false });
53
- expect(result).toBe(true);
54
- },
55
- longTestTimeout
56
- );
57
-
58
- it(
59
- 'should pass for constraint-based validation',
60
- async () => {
61
- const result = await aiExpect('Hello world!').toSatisfy('Is this a greeting?', {
62
- throws: false,
63
- });
64
- expect(result).toBe(true);
65
- },
66
- longTestTimeout
67
- );
68
-
69
- it(
70
- 'should fail for non-matching values',
71
- async () => {
72
- const result = await aiExpect('goodbye').toEqual('hello', {
73
- throws: false,
74
- });
75
- expect(result).toBe(false);
76
- },
77
- longTestTimeout
78
- );
79
-
80
- it(
81
- 'should validate content quality',
82
- async () => {
83
- const result = await aiExpect(
84
- 'This is a well-written, professional email with proper grammar.'
85
- ).toSatisfy('Is this text professional and grammatically correct?', {
86
- throws: false,
87
- });
88
- expect(result).toBe(true);
89
- },
90
- longTestTimeout
91
- );
92
-
93
- it(
94
- 'should validate data structures',
95
- async () => {
96
- const result = await aiExpect({ name: 'John Doe', age: 30, city: 'New York' }).toSatisfy(
97
- 'Does this person data look realistic?',
98
- { throws: false }
99
- );
100
- expect(result).toBe(true);
101
- },
102
- longTestTimeout
103
- );
104
-
105
- it(
106
- 'should handle business logic validation',
107
- async () => {
108
- const result = await aiExpect(
109
- 'Increase marketing budget by 20% for Q4 to boost holiday sales'
110
- ).toSatisfy('Is this recommendation specific and actionable?', {
111
- throws: false,
112
- });
113
- expect(result).toBe(true);
114
- },
115
- longTestTimeout
116
- );
117
-
118
- it(
119
- 'should throw by default on failure',
120
- async () => {
121
- await expect(async () => {
122
- await aiExpect('hello').toEqual('goodbye');
123
- }).rejects.toThrow('LLM assertion failed');
124
- },
125
- longTestTimeout
126
- );
127
- });
@@ -1,139 +0,0 @@
1
- import Ajv from 'ajv';
2
- import fs from 'node:fs/promises';
3
- import { describe, expect, it, beforeAll, afterAll } from 'vitest';
4
- import { expect as aiExpect } from '../../chains/expect/index.js';
5
- import { longTestTimeout } from '../../constants/common.js';
6
- import { fileURLToPath } from 'url';
7
- import { dirname, join } from 'path';
8
-
9
- import intent from './index.js';
10
-
11
- const __filename = fileURLToPath(import.meta.url);
12
- const __dirname = dirname(__filename);
13
-
14
- async function getIntentSchema() {
15
- return JSON.parse(await fs.readFile(join(__dirname, '../../json-schemas/intent.json')));
16
- }
17
-
18
- const examples = [
19
- {
20
- inputs: { text: 'Give me a flight to Burgas' },
21
- want: { resultSchema: getIntentSchema },
22
- },
23
- {
24
- inputs: {
25
- text: 'Lookup a song by the quote \
26
- "I just gotta tell you how I\'m feeling"',
27
- },
28
- want: { resultSchema: getIntentSchema },
29
- },
30
- ];
31
-
32
- describe('Intent verblet', () => {
33
- // Set environment mode to 'none' for all tests to avoid throwing
34
- const originalMode = process.env.LLM_EXPECT_MODE;
35
-
36
- beforeAll(() => {
37
- process.env.LLM_EXPECT_MODE = 'none';
38
- });
39
-
40
- afterAll(() => {
41
- if (originalMode !== undefined) {
42
- process.env.LLM_EXPECT_MODE = originalMode;
43
- } else {
44
- delete process.env.LLM_EXPECT_MODE;
45
- }
46
- });
47
-
48
- examples.forEach((example) => {
49
- it(
50
- example.inputs.text,
51
- async () => {
52
- const result = await intent({ text: example.inputs.text });
53
-
54
- if (example.want.resultSchema) {
55
- const schema = await example.want.resultSchema();
56
- const ajv = new Ajv();
57
- const validate = ajv.compile(schema);
58
-
59
- const isValid = validate(result);
60
- if (!isValid) {
61
- console.error('Validation errors:');
62
- console.error(validate.errors);
63
- console.error('Returned result:');
64
- console.error(JSON.stringify(result, null, 2));
65
- }
66
- expect(isValid).toStrictEqual(true);
67
-
68
- // LLM assertion to validate intent extraction quality
69
- const intentMakesSense = await aiExpect(
70
- `Original text: "${example.inputs.text}" was parsed into an intent object`
71
- ).toSatisfy('Does this seem like a reasonable intent extraction?');
72
- expect(intentMakesSense).toBe(true);
73
-
74
- // Additional assertion for intent completeness
75
- const hasBasicInfo = await aiExpect(JSON.stringify(result)).toSatisfy(
76
- 'Does this intent object contain some useful information?'
77
- );
78
- expect(hasBasicInfo).toBe(true);
79
- }
80
- },
81
- longTestTimeout
82
- );
83
- });
84
-
85
- it(
86
- 'should extract travel booking intent correctly',
87
- async () => {
88
- const travelRequest =
89
- 'Book me a round-trip flight from New York to Tokyo for next month, preferably business class';
90
- const result = await intent({ text: travelRequest });
91
-
92
- // Traditional schema validation
93
- const schema = await getIntentSchema();
94
- const ajv = new Ajv();
95
- const validate = ajv.compile(schema);
96
- expect(validate(result)).toBe(true);
97
-
98
- // LLM assertions for travel-specific validation
99
- const isTravelRelated = await aiExpect(`Intent extracted from: "${travelRequest}"`).toSatisfy(
100
- 'Is this request related to travel or transportation?'
101
- );
102
- expect(isTravelRelated).toBe(true);
103
-
104
- const hasLocationInfo = await aiExpect(JSON.stringify(result)).toSatisfy(
105
- 'Does this intent mention any locations or destinations?'
106
- );
107
- expect(hasLocationInfo).toBe(true);
108
- },
109
- longTestTimeout
110
- );
111
-
112
- it(
113
- 'should handle entertainment search intent',
114
- async () => {
115
- const musicQuery =
116
- 'Find that song that goes "Never gonna give you up, never gonna let you down"';
117
- const result = await intent({ text: musicQuery });
118
-
119
- // Schema validation
120
- const schema = await getIntentSchema();
121
- const ajv = new Ajv();
122
- const validate = ajv.compile(schema);
123
- expect(validate(result)).toBe(true);
124
-
125
- // LLM assertion for entertainment intent
126
- const isEntertainmentRelated = await aiExpect(
127
- `Intent extracted from: "${musicQuery}"`
128
- ).toSatisfy('Is this request related to music or entertainment?');
129
- expect(isEntertainmentRelated).toBe(true);
130
-
131
- // Validate that the intent captures the search criteria
132
- const mentionsLyrics = await aiExpect(JSON.stringify(result)).toSatisfy(
133
- 'Does this intent mention song lyrics or music search?'
134
- );
135
- expect(mentionsLyrics).toBe(true);
136
- },
137
- longTestTimeout
138
- );
139
- });
@@ -1,60 +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 { constants as promptConstants } from '../../prompts/index.js';
6
-
7
- const { contentIsQuestion } = promptConstants;
8
-
9
- // Get the directory of this module
10
- const __filename = fileURLToPath(import.meta.url);
11
- const __dirname = path.dirname(__filename);
12
-
13
- /**
14
- * Load the JSON schema for intent results
15
- * @returns {Promise<Object>} JSON schema for validation
16
- */
17
- async function getIntentSchema() {
18
- const schemaPath = path.resolve(__dirname, '../../json-schemas/intent.json');
19
- return JSON.parse(await fs.readFile(schemaPath, 'utf8'));
20
- }
21
-
22
- /**
23
- * Create model options for structured outputs
24
- * @param {string|Object} llm - LLM model name or configuration object
25
- * @returns {Promise<Object>} Model options for chatGPT
26
- */
27
- async function createModelOptions(llm = 'fastGoodCheap') {
28
- const schema = await getIntentSchema();
29
-
30
- const responseFormat = {
31
- type: 'json_schema',
32
- json_schema: {
33
- name: 'intent_result',
34
- schema,
35
- },
36
- };
37
-
38
- if (typeof llm === 'string') {
39
- return {
40
- modelName: llm,
41
- response_format: responseFormat,
42
- };
43
- } else {
44
- return {
45
- ...llm,
46
- response_format: responseFormat,
47
- };
48
- }
49
- }
50
-
51
- export default async function intent({ text, config = {} } = {}) {
52
- const { llm, ...options } = config;
53
- const prompt = `${contentIsQuestion} What is the intent of this text?\n\n${text}`;
54
-
55
- const modelOptions = await createModelOptions(llm);
56
- const response = await chatGPT(prompt, { modelOptions, ...options });
57
-
58
- // With structured outputs, response should already be parsed
59
- return typeof response === 'string' ? JSON.parse(response) : response;
60
- }
@@ -1,31 +0,0 @@
1
- import { describe, expect, it, vi } from 'vitest';
2
-
3
- import intent from './index.js';
4
-
5
- vi.mock('../../lib/chatgpt/index.js', () => ({
6
- default: vi.fn().mockImplementation((text) => {
7
- if (/a flight to/.test(text)) {
8
- return '{}';
9
- }
10
- return 'undefined';
11
- }),
12
- }));
13
-
14
- const examples = [
15
- {
16
- name: 'Basic usage',
17
- inputs: { text: 'Give me a flight to Burgas' },
18
- want: { typeOfResult: 'object' },
19
- },
20
- ];
21
-
22
- describe('Intent verblet', () => {
23
- examples.forEach((example) => {
24
- it(example.name, async () => {
25
- const result = await intent({ text: example.inputs.text });
26
- if (example.want.typeOfResult) {
27
- expect(typeof result).toStrictEqual(example.want.typeOfResult);
28
- }
29
- });
30
- });
31
- });
@@ -1,16 +0,0 @@
1
- # intersection
2
-
3
- Find common threads between multiple items using an LLM. The verblet checks every combination from pairs up to the full set. If no relationship is obvious, an empty array is returned.
4
-
5
- ```javascript
6
- import intersection from './index.js';
7
-
8
- await intersection(['smartphone', 'tablet', 'laptop']);
9
- // => ['Portable electronics', 'Portable computers']
10
-
11
- // Provide custom instructions for how to find intersections
12
- await intersection(['car', 'bicycle', 'train'], {
13
- instructions: 'focus on transportation methods available in a city',
14
- });
15
- // => ['Wheeled vehicles', 'Public transit']
16
- ```
@@ -1,89 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import intersection from './index.js';
3
- import { longTestTimeout } from '../../constants/common.js';
4
- import aiExpect from '../expect/index.js';
5
-
6
- describe('intersection examples', () => {
7
- it(
8
- 'finds commonalities among devices',
9
- async () => {
10
- const result = await intersection(['smartphone', 'laptop', 'tablet']);
11
- expect(Array.isArray(result), `Saw: ${JSON.stringify(result)}`).toBe(true);
12
-
13
- // LLM assertion to verify the intersection contains meaningful commonalities
14
- await aiExpect(result).toSatisfy(
15
- 'should be an array of strings that could reasonably represent commonalities between technology devices',
16
- {
17
- context: 'Testing intersection verblet with electronic devices',
18
- }
19
- );
20
- },
21
- longTestTimeout
22
- );
23
-
24
- it(
25
- 'finds commonalities among animals',
26
- async () => {
27
- const result = await intersection(['dog', 'cat', 'bird']);
28
- expect(Array.isArray(result), `Saw: ${JSON.stringify(result)}`).toBe(true);
29
-
30
- // LLM assertion for animal traits - be more lenient
31
- await aiExpect(result).toSatisfy(
32
- 'should be an array that represents some form of analysis or commonalities related to animals',
33
- {
34
- context: 'Testing intersection verblet with animals',
35
- }
36
- );
37
-
38
- // Just check that it's an array - don't require specific content
39
- expect(Array.isArray(result)).toBe(true);
40
- },
41
- longTestTimeout
42
- );
43
-
44
- it(
45
- 'handles abstract concepts',
46
- async () => {
47
- const result = await intersection(['love', 'friendship', 'trust']);
48
- expect(Array.isArray(result), `Saw: ${JSON.stringify(result)}`).toBe(true);
49
-
50
- // LLM assertion for abstract concept intersections - be more specific
51
- await aiExpect(result).toSatisfy(
52
- 'should be an array of strings representing common emotional or relational concepts that love, friendship, and trust share (like emotional connection, mutual respect, care, etc.)',
53
- {
54
- context: 'Testing intersection verblet with abstract concepts: love, friendship, trust',
55
- }
56
- );
57
-
58
- // Verify it's a non-empty array with string elements
59
- expect(Array.isArray(result)).toBe(true);
60
- expect(result.length).toBeGreaterThan(0);
61
- expect(result.every((item) => typeof item === 'string')).toBe(true);
62
- },
63
- longTestTimeout
64
- );
65
-
66
- it(
67
- 'works with single item',
68
- async () => {
69
- const result = await intersection(['bicycle']);
70
- expect(Array.isArray(result), `Saw: ${JSON.stringify(result)}`).toBe(true);
71
-
72
- // Single items should return empty array based on the implementation
73
- expect(result.length).toBe(0);
74
- },
75
- longTestTimeout
76
- );
77
-
78
- it(
79
- 'handles empty input gracefully',
80
- async () => {
81
- const result = await intersection([]);
82
- expect(Array.isArray(result), `Saw: ${JSON.stringify(result)}`).toBe(true);
83
-
84
- // Empty input should return empty array
85
- expect(result.length).toBe(0);
86
- },
87
- longTestTimeout
88
- );
89
- });
@@ -1,84 +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 { contentIsQuestion, tryCompleteData, onlyJSONStringArray } = 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 intersection results
16
- * @returns {Promise<Object>} JSON schema for validation
17
- */
18
- async function getIntersectionSchema() {
19
- const schemaPath = path.join(__dirname, 'intersection-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 getIntersectionSchema();
30
-
31
- const responseFormat = {
32
- type: 'json_schema',
33
- json_schema: {
34
- name: 'intersection_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
- export const buildPrompt = (items, { instructions } = {}) => {
53
- const itemsList = items.join(' | ');
54
- const itemsBlock = wrapVariable(itemsList, { tag: 'items' });
55
- const intro =
56
- instructions ||
57
- 'List the common features, instances, or relational links that all items share.';
58
-
59
- return `${contentIsQuestion} ${intro}
60
-
61
- ${itemsBlock}
62
-
63
- The array should specify items without context, groupings, or any other data--just names.
64
-
65
- ${tryCompleteData} ${onlyJSONStringArray}`;
66
- };
67
-
68
- export default async function intersection(items, config = {}) {
69
- if (!Array.isArray(items) || items.length < 2) return [];
70
-
71
- const { llm, ...options } = config;
72
- const modelOptions = await createModelOptions(llm);
73
-
74
- const output = await chatGPT(buildPrompt(items, options), {
75
- modelOptions,
76
- });
77
-
78
- // With structured outputs, response should already be parsed and validated
79
- const parsed = typeof output === 'string' ? JSON.parse(output) : output;
80
-
81
- // Extract the items array from the object structure
82
- const resultArray = parsed?.items || parsed;
83
- return Array.isArray(resultArray) ? resultArray.filter(Boolean) : [];
84
- }
@@ -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
- });