@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,171 +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 { onlyJSON, strictFormat } from '../../prompts/constants.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 central tendency results
13
- * @returns {Promise<Object>} JSON schema for validation
14
- */
15
- async function getCentralTendencySchema() {
16
- const schemaPath = path.join(__dirname, 'central-tendency-result.json');
17
- return JSON.parse(await fs.readFile(schemaPath, 'utf8'));
18
- }
19
-
20
- /**
21
- * Core prompt template for central tendency evaluation using cognitive science principles.
22
- * Suitable for both individual and bulk processing.
23
- */
24
- export const CENTRAL_TENDENCY_PROMPT = `Use cognitive science principles of prototype theory and family resemblance:
25
-
26
- {context}
27
- {coreFeatures}
28
-
29
- COGNITIVE PRINCIPLES:
30
- 1. Prototype Theory: Categories have graded structure with central and peripheral members
31
- 2. Family Resemblance: Members share overlapping features without identical characteristics
32
- 3. Feature Analysis: Consider both core (definitional) and characteristic (typical) features
33
- 4. Functional Centrality: Assess how well the item serves the category's purpose
34
-
35
- ASSESSMENT CRITERIA:
36
- - Feature overlap with seed items
37
- - Possession of core definitional features
38
- - Functional alignment with category purpose
39
- - Typicality relative to category prototype
40
-
41
- CENTRALITY SCORING GUIDE (use precise decimals):
42
- • 0.0-0.1: Not a category member (completely unrelated)
43
- • 0.1-0.2: Extremely peripheral (minimal connection, metaphorical only)
44
- • 0.2-0.3: Peripheral member (weak connection, few shared features)
45
- • 0.3-0.4: Marginal member (some shared features but atypical)
46
- • 0.4-0.5: Borderline member (mixed typical/atypical features)
47
- • 0.5-0.6: Atypical but clear member (definitionally belongs but unusual)
48
- • 0.6-0.7: Moderately typical (good example with some variations)
49
- • 0.7-0.8: Highly typical (strong example, most expected features)
50
- • 0.8-0.9: Very prototypical (excellent example, nearly all expected features)
51
- • 0.9-1.0: Maximally prototypical (perfect/ideal example of the category)
52
-
53
- {outputRequirements}`;
54
-
55
- /**
56
- * Build a prompt for evaluating centrality
57
- * @param {string} item - The item to evaluate (for single) or placeholder for bulk
58
- * @param {string[]} seedItems - Array of seed items for comparison
59
- * @param {Object} config - Configuration options
60
- * @returns {string} Complete prompt
61
- */
62
- export function buildCentralTendencyPrompt(
63
- item,
64
- seedItems,
65
- { context = '', coreFeatures = [], outputRequirements = null } = {}
66
- ) {
67
- const contextLine = context ? `Context: ${context}` : '';
68
- const coreFeaturesLine =
69
- coreFeatures.length > 0 ? `Core Features: ${coreFeatures.join(', ')}` : '';
70
-
71
- // Default structured output requirements for individual verblet use
72
- const defaultOutputRequirements = `OUTPUT REQUIREMENTS:
73
- ${onlyJSON}
74
- ${strictFormat}
75
-
76
- Required JSON structure:
77
- {
78
- "score": <number between 0.0 and 1.0>,
79
- "reason": "<brief explanation of the centrality assessment>",
80
- "confidence": <number between 0.0 and 1.0 indicating confidence in the assessment>
81
- }
82
-
83
- The "reason" should briefly explain why the item received its centrality score based on feature overlap, typicality, and functional alignment with the seed items.
84
- The "confidence" should reflect how certain you are about the assessment (higher for clear cases, lower for borderline cases).`;
85
-
86
- const outputRequirementsLine = outputRequirements || defaultOutputRequirements;
87
-
88
- const prompt = CENTRAL_TENDENCY_PROMPT.replace('{context}', contextLine)
89
- .replace('{coreFeatures}', coreFeaturesLine)
90
- .replace('{outputRequirements}', outputRequirementsLine);
91
-
92
- return `Evaluate how central "${item}" is among these category members: ${seedItems.join(', ')}
93
-
94
- ${prompt}`;
95
- }
96
-
97
- /**
98
- * Create model options for structured outputs
99
- * @param {string|Object} llm - LLM model name or configuration object
100
- * @param {string} schemaName - Name for the JSON schema
101
- * @param {Object} [customSchema] - Custom schema to use instead of default
102
- * @returns {Promise<Object>} Model options for chatGPT
103
- */
104
- async function createModelOptions(
105
- llm = 'fastGoodCheap',
106
- schemaName = 'central_tendency_result',
107
- customSchema = null
108
- ) {
109
- const schema = customSchema || (await getCentralTendencySchema());
110
-
111
- const responseFormat = {
112
- type: 'json_schema',
113
- json_schema: {
114
- name: schemaName,
115
- schema,
116
- },
117
- };
118
-
119
- if (typeof llm === 'string') {
120
- return {
121
- modelName: llm,
122
- response_format: responseFormat,
123
- };
124
- } else {
125
- return {
126
- ...llm,
127
- response_format: responseFormat,
128
- };
129
- }
130
- }
131
-
132
- /**
133
- * Parse response from chatGPT
134
- * @param {string|Object} response - Response from chatGPT
135
- * @returns {Object} Parsed response object
136
- */
137
- function parseResponse(response) {
138
- return typeof response === 'string' ? JSON.parse(response) : response;
139
- }
140
-
141
- /**
142
- * Evaluate how central an item is among category members using cognitive science principles.
143
- *
144
- * Based on prototype theory and family resemblance, this function assesses graded typicality
145
- * by analyzing feature overlap, core characteristics, and functional alignment with seed items.
146
- *
147
- * @param {string} item - The item to evaluate for centrality
148
- * @param {string[]} seedItems - Array of known category members for comparison
149
- * @param {Object} [config={}] - Configuration options
150
- * @param {string} [config.context=''] - Context description for evaluation
151
- * @param {string[]} [config.coreFeatures=[]] - Known core/definitional features of the category
152
- * @param {string} [config.llm='fastGoodCheap'] - LLM model to use
153
- * @returns {Promise<{score: number, reason: string, confidence: number}>}
154
- */
155
- export default async function centralTendency(item, seedItems, config = {}) {
156
- if (!item || typeof item !== 'string') {
157
- throw new Error('Item must be a non-empty string');
158
- }
159
-
160
- if (!Array.isArray(seedItems) || seedItems.length === 0) {
161
- throw new Error('seedItems must be a non-empty array');
162
- }
163
-
164
- const { context = '', coreFeatures = [], llm = 'fastGoodCheap' } = config;
165
-
166
- const prompt = buildCentralTendencyPrompt(item, seedItems, { context, coreFeatures });
167
- const modelOptions = await createModelOptions(llm, 'central_tendency_result');
168
-
169
- const response = await chatGPT(prompt, { modelOptions });
170
- return parseResponse(response);
171
- }
@@ -1,148 +0,0 @@
1
- import { describe, it, expect, vi, beforeEach } from 'vitest';
2
- import centralTendency from './index.js';
3
-
4
- // Mock the LLM service
5
- vi.mock('../../lib/chatgpt/index.js', () => ({
6
- default: vi.fn(),
7
- }));
8
-
9
- import chatGPT from '../../lib/chatgpt/index.js';
10
-
11
- describe('centralTendency', () => {
12
- beforeEach(() => {
13
- vi.clearAllMocks();
14
- });
15
-
16
- it('evaluates centrality with config object', async () => {
17
- const mockResponse = {
18
- score: 0.85,
19
- reason: 'High feature overlap with seed items',
20
- confidence: 0.9,
21
- };
22
-
23
- chatGPT.mockResolvedValue(mockResponse);
24
-
25
- const result = await centralTendency('robin', ['sparrow', 'bluejay', 'cardinal'], {
26
- context: 'Evaluate based on typical bird characteristics',
27
- coreFeatures: ['feathers', 'beak', 'lays eggs'],
28
- llm: 'fastGoodCheap',
29
- });
30
-
31
- expect(result).toEqual({
32
- score: 0.85,
33
- reason: 'High feature overlap with seed items',
34
- confidence: 0.9,
35
- });
36
-
37
- expect(chatGPT).toHaveBeenCalledWith(
38
- expect.stringContaining('Evaluate how central "robin" is among these category members'),
39
- { modelOptions: expect.objectContaining({ modelName: 'fastGoodCheap' }) }
40
- );
41
- });
42
-
43
- it('uses default LLM model when not specified', async () => {
44
- const mockResponse = {
45
- score: 0.75,
46
- reason: 'Good match',
47
- confidence: 0.8,
48
- };
49
-
50
- chatGPT.mockResolvedValue(mockResponse);
51
-
52
- const result = await centralTendency('penguin', ['robin', 'sparrow'], {
53
- context: 'Bird evaluation',
54
- });
55
-
56
- expect(result.score).toBe(0.75);
57
- expect(chatGPT).toHaveBeenCalledWith(expect.any(String), {
58
- modelOptions: expect.objectContaining({ modelName: 'fastGoodCheap' }),
59
- });
60
- });
61
-
62
- it('throws error for invalid item', async () => {
63
- await expect(centralTendency('', ['seed1', 'seed2'])).rejects.toThrow(
64
- 'Item must be a non-empty string'
65
- );
66
- await expect(centralTendency(null, ['seed1', 'seed2'])).rejects.toThrow(
67
- 'Item must be a non-empty string'
68
- );
69
- });
70
-
71
- it('throws error for invalid seedItems', async () => {
72
- await expect(centralTendency('item', [])).rejects.toThrow(
73
- 'seedItems must be a non-empty array'
74
- );
75
- await expect(centralTendency('item', null)).rejects.toThrow(
76
- 'seedItems must be a non-empty array'
77
- );
78
- });
79
-
80
- it('handles JSON string response', async () => {
81
- const mockResponse = JSON.stringify({
82
- score: 0.6,
83
- reason: 'Moderate centrality',
84
- confidence: 0.7,
85
- });
86
-
87
- chatGPT.mockResolvedValue(mockResponse);
88
-
89
- const result = await centralTendency('item', ['seed1', 'seed2']);
90
-
91
- expect(result).toEqual({
92
- score: 0.6,
93
- reason: 'Moderate centrality',
94
- confidence: 0.7,
95
- });
96
- });
97
-
98
- it('handles object response directly', async () => {
99
- const mockResponse = {
100
- score: 0.8,
101
- reason: 'High centrality',
102
- confidence: 0.9,
103
- };
104
-
105
- chatGPT.mockResolvedValue(mockResponse);
106
-
107
- const result = await centralTendency('item', ['seed1', 'seed2']);
108
-
109
- expect(result).toEqual(mockResponse);
110
- });
111
-
112
- it('builds correct prompt with context and core features', async () => {
113
- const mockResponse = {
114
- score: 0.7,
115
- reason: 'Test result',
116
- confidence: 0.8,
117
- };
118
-
119
- chatGPT.mockResolvedValue(mockResponse);
120
-
121
- await centralTendency('robin', ['sparrow', 'bluejay'], {
122
- context: 'Bird evaluation context',
123
- coreFeatures: ['feathers', 'beak', 'flight'],
124
- });
125
-
126
- const calledPrompt = chatGPT.mock.calls[0][0];
127
- expect(calledPrompt).toContain('Context: Bird evaluation context');
128
- expect(calledPrompt).toContain('Core Features: feathers, beak, flight');
129
- expect(calledPrompt).toContain('sparrow, bluejay');
130
- });
131
-
132
- it('uses JSON schema validation', async () => {
133
- const mockResponse = {
134
- score: 0.6,
135
- reason: 'Assessment with schema',
136
- confidence: 0.8,
137
- };
138
-
139
- chatGPT.mockResolvedValue(mockResponse);
140
-
141
- await centralTendency('item', ['seed1', 'seed2'], {});
142
-
143
- const modelOptions = chatGPT.mock.calls[0][1].modelOptions;
144
- expect(modelOptions).toHaveProperty('response_format');
145
- expect(modelOptions.response_format.type).toBe('json_schema');
146
- expect(modelOptions.response_format.json_schema.name).toBe('central_tendency_result');
147
- });
148
- });
@@ -1,30 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
-
3
- import enumValue from './index.js';
4
- import { longTestTimeout } from '../../constants/common.js';
5
-
6
- const examples = [
7
- {
8
- inputs: {
9
- text: 'What is the top color on a traffic light',
10
- enum: { green: 1, yellow: 1, red: 1, purple: 1 },
11
- },
12
- want: { result: 'red' },
13
- },
14
- ];
15
-
16
- describe('Enum verblet', () => {
17
- examples.forEach((example) => {
18
- it(
19
- example.inputs.text,
20
- async () => {
21
- const result = await enumValue(example.inputs.text, example.inputs.enum);
22
-
23
- if (example.want.result) {
24
- expect(result).toStrictEqual(example.want.result);
25
- }
26
- },
27
- longTestTimeout
28
- );
29
- });
30
- });
@@ -1,18 +0,0 @@
1
- import chatGPT from '../../lib/chatgpt/index.js';
2
- import stripResponse from '../../lib/strip-response/index.js';
3
- import toEnum from '../../lib/to-enum/index.js';
4
- import { asEnum, constants } from '../../prompts/index.js';
5
-
6
- const { asUndefinedByDefault, contentIsQuestion, explainAndSeparate } = constants;
7
-
8
- export default async (text, enumVal, config = {}) => {
9
- const { llm, ...options } = config;
10
- const enumText = `${contentIsQuestion} ${text}\n\n${explainAndSeparate}
11
-
12
- ${asEnum(enumVal)} ${asUndefinedByDefault}`;
13
-
14
- return toEnum(
15
- stripResponse(await chatGPT(enumText, { modelOptions: { ...llm }, ...options })),
16
- enumVal
17
- );
18
- };
@@ -1,35 +0,0 @@
1
- import { describe, expect, it, vi } from 'vitest';
2
-
3
- import enumValue from './index.js';
4
-
5
- vi.mock('../../lib/chatgpt/index.js', () => ({
6
- default: vi.fn().mockImplementation((text) => {
7
- if (/traffic light/.test(text)) {
8
- return 'red';
9
- }
10
- return 'undefined';
11
- }),
12
- }));
13
-
14
- const examples = [
15
- {
16
- name: 'Basic usage',
17
- inputs: {
18
- text: 'What is the top color on a traffic light',
19
- enum: { green: 1, yellow: 1, red: 1, purple: 1 },
20
- },
21
- want: { result: 'red' },
22
- },
23
- ];
24
-
25
- describe('Enum verblet', () => {
26
- examples.forEach((example) => {
27
- it(example.name, async () => {
28
- const result = await enumValue(example.inputs.text, example.inputs.enum);
29
-
30
- if (example.want.result) {
31
- expect(result).toStrictEqual(example.want.result);
32
- }
33
- });
34
- });
35
- });
@@ -1,64 +0,0 @@
1
- # LLM Expect
2
-
3
- Make intelligent assertions using natural language. A single LLM call that validates content based on meaning, intent, and context.
4
-
5
- ## Quick Start
6
-
7
- ```javascript
8
- import expect, { llmAssert } from './index.js';
9
-
10
- // Simple equality check (throws on failure)
11
- await expect("hello").toEqual("hello");
12
- // ✅ Passes silently
13
-
14
- // Constraint-based validation
15
- await expect("Hello world!").toSatisfy("Is this a greeting?");
16
- // ✅ Passes silently
17
-
18
- // Failed assertion throws
19
- try {
20
- await expect("goodbye").toEqual("hello");
21
- } catch (error) {
22
- console.log(error.message);
23
- // "LLM assertion failed: Does the actual value strictly equal the expected value?"
24
- }
25
-
26
- // Direct helper with custom options
27
- const passed = await llmAssert({
28
- actual: "hello",
29
- equals: "hello",
30
- llm: { temperature: 0 },
31
- throws: false,
32
- });
33
-
34
- // Custom message when the assertion fails
35
- await expect("bad").toEqual("good", {
36
- message: ({ actual, equals }) => `Expected ${equals} but got ${actual}`,
37
- });
38
- ```
39
-
40
- Use `throws: false` to return a boolean instead of throwing when the assertion fails.
41
-
42
- ## Enhanced Chain Implementation
43
-
44
- For advanced debugging, detailed error analysis, and enhanced features, use the **[expect chain](../../chains/expect/)**:
45
-
46
- ### Environment Modes
47
-
48
- ```bash
49
- # Silent operation (default)
50
- export LLM_EXPECT_MODE=none
51
-
52
- # Log debugging advice on failures
53
- export LLM_EXPECT_MODE=info
54
-
55
- # Throw with detailed debugging advice
56
- export LLM_EXPECT_MODE=error
57
- ```
58
-
59
- ## Best Practices
60
-
61
- - **Be specific**: Use clear, detailed constraints
62
- - **Test qualitatively**: Verify qualitative details with a clear yes/no answer
63
- - **Use robust constraints**: Write criteria to pass under a wide range of input hallucinations. Assert cases that classical software can't. Tune the level of rigorousness to the model performing the eval.
64
- - **Performance**: Remember this makes an LLM call - use judiciously
@@ -1,109 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
-
3
- import aiExpect from './index.js';
4
- import { longTestTimeout } from '../../constants/common.js';
5
-
6
- const examples = [
7
- {
8
- inputs: {
9
- actual: 'hello',
10
- expected: 'hello',
11
- },
12
- want: { result: true },
13
- },
14
- {
15
- inputs: {
16
- actual: 'hello',
17
- expected: 'goodbye',
18
- },
19
- want: { result: false },
20
- },
21
- {
22
- inputs: {
23
- actual: 'Hello world!',
24
- constraint: 'Is this a greeting?',
25
- },
26
- want: { result: true },
27
- },
28
- {
29
- inputs: {
30
- actual: 'Goodbye cruel world',
31
- constraint: 'Is this a greeting?',
32
- },
33
- want: { result: false },
34
- },
35
- {
36
- inputs: {
37
- actual: 'This is a well-written, professional email with proper grammar and clear intent.',
38
- constraint: 'Is this text professional and grammatically correct?',
39
- },
40
- want: { result: true },
41
- },
42
- {
43
- inputs: {
44
- actual: { name: 'John Doe', age: 30, city: 'New York' },
45
- constraint: 'Does this person data look realistic?',
46
- },
47
- want: { result: true },
48
- },
49
- ];
50
-
51
- describe('LLM Expect Verblet', () => {
52
- examples.forEach((example) => {
53
- const description = example.inputs.constraint
54
- ? `${JSON.stringify(example.inputs.actual).slice(0, 30)}... - ${example.inputs.constraint}`
55
- : `${JSON.stringify(example.inputs.actual)} === ${JSON.stringify(example.inputs.expected)}`;
56
-
57
- it(
58
- description,
59
- async () => {
60
- const result =
61
- example.inputs.expected !== undefined
62
- ? await aiExpect(example.inputs.actual).toEqual(example.inputs.expected, {
63
- throws: false,
64
- })
65
- : await aiExpect(example.inputs.actual).toSatisfy(example.inputs.constraint, {
66
- throws: false,
67
- });
68
-
69
- expect(result).toBe(example.want.result);
70
- },
71
- longTestTimeout
72
- );
73
- });
74
-
75
- it(
76
- 'should throw by default on failure',
77
- async () => {
78
- await expect(async () => {
79
- await aiExpect('hello').toEqual('goodbye');
80
- }).rejects.toThrow('LLM assertion failed');
81
- },
82
- longTestTimeout
83
- );
84
-
85
- it(
86
- 'should not throw when throws option is false',
87
- async () => {
88
- const result = await aiExpect('hello').toEqual('goodbye', { throws: false });
89
- expect(result).toBe(false);
90
- },
91
- longTestTimeout
92
- );
93
-
94
- it(
95
- 'should handle business logic validation',
96
- async () => {
97
- const businessRecommendation =
98
- 'Increase marketing budget by 20% for Q4 to boost holiday sales and target demographics aged 25-45 through social media campaigns';
99
-
100
- const result = await aiExpect(businessRecommendation).toSatisfy(
101
- 'Is this recommendation specific, actionable, and includes measurable targets?',
102
- { throws: false }
103
- );
104
-
105
- expect(result).toBe(true);
106
- },
107
- longTestTimeout
108
- );
109
- });
@@ -1,75 +0,0 @@
1
- import chatgpt from '../../lib/chatgpt/index.js';
2
-
3
- function buildEqualityPrompt({ actual, expected, context }) {
4
- return `Does the actual value strictly equal the expected value?\n\nActual: ${JSON.stringify(
5
- actual,
6
- null,
7
- 2
8
- )}\nExpected: ${JSON.stringify(expected, null, 2)}\n\n${
9
- context ? `Context: ${JSON.stringify(context, null, 2)}\n` : ''
10
- }Answer only "True" or "False".`;
11
- }
12
-
13
- function buildConstraintPrompt({ actual, constraint, context }) {
14
- return `Given this constraint: "${constraint}"\n\nActual value: ${JSON.stringify(
15
- actual,
16
- null,
17
- 2
18
- )}\n\n${
19
- context ? `Additional context: ${JSON.stringify(context, null, 2)}\n` : ''
20
- }Does the actual value satisfy the constraint? Answer only "True" or "False".`;
21
- }
22
-
23
- export async function llmAssert({
24
- actual,
25
- equals,
26
- constraint,
27
- context,
28
- throws = true,
29
- message,
30
- llm = {},
31
- }) {
32
- if (equals === undefined && !constraint)
33
- throw new TypeError('Provide either "equals" or "constraint".');
34
-
35
- const prompt =
36
- equals !== undefined
37
- ? buildEqualityPrompt({ actual, expected: equals, context })
38
- : buildConstraintPrompt({ actual, constraint, context });
39
-
40
- const answer = await chatgpt(prompt, { modelOptions: llm });
41
- const text = typeof answer === 'string' ? answer : answer.content;
42
- const passed = /^true$/i.test(text.trim());
43
-
44
- if (!passed && throws) {
45
- let msg;
46
- if (typeof message === 'function') {
47
- msg = message({ actual, equals, constraint });
48
- } else {
49
- msg = message;
50
- }
51
-
52
- if (!msg) {
53
- msg =
54
- equals !== undefined
55
- ? 'LLM assertion failed: Does the actual value strictly equal the expected value?'
56
- : `LLM assertion failed: ${constraint}`;
57
- }
58
-
59
- throw new Error(msg);
60
- }
61
-
62
- return passed;
63
- }
64
-
65
- export default function expect(actual, shared = {}) {
66
- const run = (payload, opts) => llmAssert({ actual, ...payload, ...shared, ...opts });
67
- return {
68
- toEqual(expected, opts) {
69
- return run({ equals: expected }, opts);
70
- },
71
- toSatisfy(constraint, opts) {
72
- return run({ constraint }, opts);
73
- },
74
- };
75
- }