@far-world-labs/verblets 0.1.1 → 0.1.3

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 (300) hide show
  1. package/.cursor/launch.json +30 -0
  2. package/.cursor/settings.json +20 -0
  3. package/.github/workflows/branch-protection.yml +22 -0
  4. package/.github/workflows/ci.yml +120 -0
  5. package/.prettierrc +6 -0
  6. package/.release-it.json +4 -1
  7. package/.vscode/launch.json +31 -0
  8. package/AGENTS.md +220 -0
  9. package/DEVELOPING.md +105 -0
  10. package/README.md +254 -0
  11. package/eslint.config.js +80 -0
  12. package/package.json +29 -17
  13. package/scripts/generate-test/index.js +29 -3
  14. package/scripts/runner/index.js +26 -0
  15. package/scripts/simple-editor/index.js +29 -18
  16. package/scripts/summarize-files/index.js +28 -4
  17. package/src/chains/README.md +30 -0
  18. package/src/chains/anonymize/README.md +21 -0
  19. package/src/chains/anonymize/index.examples.js +75 -0
  20. package/src/chains/anonymize/index.js +121 -0
  21. package/src/chains/anonymize/index.spec.js +78 -0
  22. package/src/chains/bulk-central-tendency/index.examples.js +138 -0
  23. package/src/chains/bulk-central-tendency/index.js +91 -0
  24. package/src/chains/bulk-filter/README.md +21 -0
  25. package/src/chains/bulk-filter/index.examples.js +22 -0
  26. package/src/chains/bulk-filter/index.js +58 -0
  27. package/src/chains/bulk-filter/index.spec.js +38 -0
  28. package/src/chains/bulk-find/README.md +16 -0
  29. package/src/chains/bulk-find/index.examples.js +20 -0
  30. package/src/chains/bulk-find/index.js +30 -0
  31. package/src/chains/bulk-find/index.spec.js +26 -0
  32. package/src/chains/bulk-group/README.md +23 -0
  33. package/src/chains/bulk-group/index.examples.js +18 -0
  34. package/src/chains/bulk-group/index.js +34 -0
  35. package/src/chains/bulk-group/index.spec.js +41 -0
  36. package/src/chains/bulk-map/README.md +43 -0
  37. package/src/chains/bulk-map/index.examples.js +17 -0
  38. package/src/chains/bulk-map/index.js +86 -0
  39. package/src/chains/bulk-map/index.spec.js +44 -0
  40. package/src/chains/bulk-reduce/README.md +12 -0
  41. package/src/chains/bulk-reduce/index.examples.js +15 -0
  42. package/src/chains/bulk-reduce/index.js +13 -0
  43. package/src/chains/bulk-reduce/index.spec.js +25 -0
  44. package/src/chains/bulk-score/README.md +16 -0
  45. package/src/chains/bulk-score/bulk-score-result.json +18 -0
  46. package/src/chains/bulk-score/index.examples.js +22 -0
  47. package/src/chains/bulk-score/index.js +133 -0
  48. package/src/chains/bulk-score/index.spec.js +30 -0
  49. package/src/chains/category-samples/README.md +61 -0
  50. package/src/chains/category-samples/index.examples.js +103 -0
  51. package/src/chains/category-samples/index.js +134 -0
  52. package/src/chains/collect-terms/README.md +12 -0
  53. package/src/chains/collect-terms/index.examples.js +16 -0
  54. package/src/chains/collect-terms/index.js +44 -0
  55. package/src/chains/collect-terms/index.spec.js +25 -0
  56. package/src/chains/date/README.md +12 -0
  57. package/src/chains/date/index.examples.js +47 -0
  58. package/src/chains/date/index.js +74 -0
  59. package/src/chains/date/index.spec.js +62 -0
  60. package/src/chains/disambiguate/README.md +22 -0
  61. package/src/chains/disambiguate/disambiguate-meanings-result.json +16 -0
  62. package/src/chains/disambiguate/index.examples.js +18 -0
  63. package/src/chains/disambiguate/index.js +92 -0
  64. package/src/chains/disambiguate/index.spec.js +25 -0
  65. package/src/chains/dismantle/README.md +67 -0
  66. package/src/chains/dismantle/dismantle.examples.js +27 -0
  67. package/src/chains/dismantle/index.js +6 -17
  68. package/src/chains/dismantle/index.spec.js +1 -2
  69. package/src/chains/expect/README.md +171 -0
  70. package/src/chains/expect/index.examples.js +146 -0
  71. package/src/chains/expect/index.js +173 -0
  72. package/src/chains/expect/index.spec.js +324 -0
  73. package/src/chains/filter-ambiguous/README.md +11 -0
  74. package/src/chains/filter-ambiguous/index.examples.js +20 -0
  75. package/src/chains/filter-ambiguous/index.js +49 -0
  76. package/src/chains/filter-ambiguous/index.spec.js +31 -0
  77. package/src/chains/glossary/README.md +19 -0
  78. package/src/chains/glossary/index.examples.js +386 -0
  79. package/src/chains/glossary/index.js +75 -0
  80. package/src/chains/glossary/index.spec.js +19 -0
  81. package/src/chains/intersections/README.md +152 -0
  82. package/src/chains/intersections/index.examples.js +279 -0
  83. package/src/chains/intersections/index.js +366 -0
  84. package/src/chains/intersections/intersection-result.json +38 -0
  85. package/src/chains/list/index.examples.js +12 -16
  86. package/src/chains/list/index.js +106 -53
  87. package/src/chains/list/index.spec.js +8 -9
  88. package/src/chains/list/list-result.json +16 -0
  89. package/src/chains/llm-logger/README.md +208 -0
  90. package/src/chains/llm-logger/index.js +205 -0
  91. package/src/chains/llm-logger/index.spec.js +330 -0
  92. package/src/chains/questions/index.examples.js +2 -1
  93. package/src/chains/questions/index.js +14 -15
  94. package/src/chains/scan-js/index.js +6 -9
  95. package/src/chains/set-interval/README.md +81 -0
  96. package/src/chains/set-interval/index.examples.js +36 -0
  97. package/src/chains/set-interval/index.js +131 -0
  98. package/src/chains/set-interval/index.spec.js +70 -0
  99. package/src/chains/socratic/README.md +17 -0
  100. package/src/chains/socratic/index.js +64 -0
  101. package/src/chains/socratic/index.spec.js +24 -0
  102. package/src/chains/sort/index.examples.js +3 -7
  103. package/src/chains/sort/index.js +65 -15
  104. package/src/chains/sort/index.spec.js +5 -8
  105. package/src/chains/sort/sort-result.json +16 -0
  106. package/src/chains/summary-map/README.md +9 -1
  107. package/src/chains/summary-map/index.examples.js +9 -2
  108. package/src/chains/summary-map/index.js +43 -25
  109. package/src/chains/summary-map/index.spec.js +78 -3
  110. package/src/chains/test/index.js +9 -13
  111. package/src/chains/test-advice/index.js +4 -5
  112. package/src/chains/themes/README.md +20 -0
  113. package/src/chains/themes/index.examples.js +17 -0
  114. package/src/chains/themes/index.js +28 -0
  115. package/src/chains/themes/index.spec.js +19 -0
  116. package/src/chains/veiled-variants/index.examples.js +18 -0
  117. package/src/chains/veiled-variants/index.js +107 -0
  118. package/src/chains/veiled-variants/index.spec.js +40 -0
  119. package/src/constants/common.js +0 -2
  120. package/src/constants/models.js +172 -0
  121. package/src/index.js +178 -18
  122. package/src/json-schemas/README.md +13 -0
  123. package/src/json-schemas/index.js +8 -14
  124. package/src/json-schemas/schema-dot-org-photograph.json +11 -5
  125. package/src/json-schemas/schema-dot-org-place.json +78 -5
  126. package/src/lib/README.md +26 -0
  127. package/src/lib/bulk-filter/README.md +22 -0
  128. package/src/lib/bulk-filter/index.examples.js +27 -0
  129. package/src/lib/bulk-filter/index.js +63 -0
  130. package/src/lib/bulk-filter/index.spec.js +38 -0
  131. package/src/lib/bulk-find/README.md +18 -0
  132. package/src/lib/bulk-find/index.examples.js +19 -0
  133. package/src/lib/bulk-find/index.js +30 -0
  134. package/src/lib/bulk-find/index.spec.js +41 -0
  135. package/src/lib/chatgpt/index.js +63 -43
  136. package/src/lib/combinations/index.js +30 -0
  137. package/src/lib/combinations/index.spec.js +23 -0
  138. package/src/lib/functional/index.js +28 -0
  139. package/src/lib/logger-service/index.js +32 -0
  140. package/src/lib/parse-js-parts/index.js +9 -21
  141. package/src/lib/parse-llm-list/README.md +39 -0
  142. package/src/lib/parse-llm-list/index.js +54 -0
  143. package/src/lib/parse-llm-list/index.spec.js +59 -0
  144. package/src/lib/path-aliases/index.js +1 -3
  145. package/src/lib/path-aliases/index.spec.js +2 -8
  146. package/src/lib/pave/index.js +4 -4
  147. package/src/lib/pave/index.spec.js +6 -3
  148. package/src/lib/prompt-cache/index.js +14 -10
  149. package/src/lib/retry/index.js +11 -8
  150. package/src/lib/ring-buffer/README.md +460 -0
  151. package/src/lib/ring-buffer/index.js +1074 -0
  152. package/src/lib/search-best-first/city-walk.spec.js +37 -0
  153. package/src/lib/search-best-first/index.js +42 -11
  154. package/src/lib/search-best-first/index.spec.js +35 -0
  155. package/src/lib/search-js-files/index.js +44 -47
  156. package/src/lib/search-js-files/scan-file.js +10 -21
  157. package/src/lib/shorten-text/index.js +2 -7
  158. package/src/lib/shorten-text/index.spec.js +3 -3
  159. package/src/lib/strip-response/index.js +2 -7
  160. package/src/lib/template-replace/index.js +23 -0
  161. package/src/lib/template-replace/index.spec.js +60 -0
  162. package/src/lib/to-date/index.js +11 -0
  163. package/src/lib/to-number/index.js +1 -1
  164. package/src/lib/transcribe/index.js +26 -9
  165. package/src/prompts/README.md +3 -1
  166. package/src/prompts/as-object-with-schema.js +3 -8
  167. package/src/prompts/as-schema-org-text.js +10 -2
  168. package/src/prompts/code-features.js +1 -5
  169. package/src/prompts/constants.js +27 -27
  170. package/src/prompts/generate-collection.js +1 -1
  171. package/src/prompts/intent.js +16 -22
  172. package/src/prompts/select-from-threshold.js +1 -2
  173. package/src/prompts/sort.js +4 -8
  174. package/src/prompts/style.js +4 -7
  175. package/src/prompts/wrap-list.js +1 -4
  176. package/src/services/llm-model/global-overrides.spec.js +432 -0
  177. package/src/services/llm-model/index.js +234 -40
  178. package/src/services/llm-model/model.js +2 -2
  179. package/src/services/llm-model/negotiate.spec.js +447 -0
  180. package/src/services/redis/index.js +70 -7
  181. package/src/test/setup.js +20 -0
  182. package/src/verblets/README.md +26 -0
  183. package/src/verblets/auto/index.examples.js +12 -9
  184. package/src/verblets/auto/index.js +10 -10
  185. package/src/verblets/auto/index.spec.js +4 -6
  186. package/src/verblets/bool/README.md +36 -0
  187. package/src/verblets/bool/index.examples.js +53 -1
  188. package/src/verblets/bool/index.js +6 -9
  189. package/src/verblets/bool/index.spec.js +1 -3
  190. package/src/verblets/central-tendency/README.md +166 -0
  191. package/src/verblets/central-tendency/central-tendency-result.json +24 -0
  192. package/src/verblets/central-tendency/index.examples.js +196 -0
  193. package/src/verblets/central-tendency/index.js +171 -0
  194. package/src/verblets/central-tendency/index.spec.js +148 -0
  195. package/src/verblets/enum/index.examples.js +1 -4
  196. package/src/verblets/enum/index.js +7 -4
  197. package/src/verblets/expect/README.md +64 -0
  198. package/src/verblets/expect/index.examples.js +109 -0
  199. package/src/verblets/expect/index.js +75 -0
  200. package/src/verblets/expect/index.spec.js +127 -0
  201. package/src/verblets/intent/index.examples.js +95 -7
  202. package/src/verblets/intent/index.js +56 -68
  203. package/src/verblets/intersection/README.md +16 -0
  204. package/src/verblets/intersection/index.examples.js +89 -0
  205. package/src/verblets/intersection/index.js +84 -0
  206. package/src/verblets/intersection/index.spec.js +60 -0
  207. package/src/verblets/intersection/intersection-result.json +16 -0
  208. package/src/verblets/list-expand/README.md +10 -0
  209. package/src/verblets/list-expand/index.examples.js +14 -0
  210. package/src/verblets/list-expand/index.js +104 -0
  211. package/src/verblets/list-expand/index.spec.js +18 -0
  212. package/src/verblets/list-expand/list-expand-result.json +16 -0
  213. package/src/verblets/list-filter/README.md +22 -0
  214. package/src/verblets/list-filter/index.examples.js +26 -0
  215. package/src/verblets/list-filter/index.js +18 -0
  216. package/src/verblets/list-filter/index.spec.js +19 -0
  217. package/src/verblets/list-find/README.md +11 -0
  218. package/src/verblets/list-find/index.examples.js +15 -0
  219. package/src/verblets/list-find/index.js +17 -0
  220. package/src/verblets/list-find/index.spec.js +19 -0
  221. package/src/verblets/list-group/README.md +16 -0
  222. package/src/verblets/list-group/index.examples.js +16 -0
  223. package/src/verblets/list-group/index.js +112 -0
  224. package/src/verblets/list-group/index.spec.js +35 -0
  225. package/src/verblets/list-group/list-group-result.json +16 -0
  226. package/src/verblets/list-map/README.md +11 -0
  227. package/src/verblets/list-map/index.examples.js +15 -0
  228. package/src/verblets/list-map/index.js +26 -0
  229. package/src/verblets/list-map/index.spec.js +17 -0
  230. package/src/verblets/list-reduce/README.md +10 -0
  231. package/src/verblets/list-reduce/index.examples.js +14 -0
  232. package/src/verblets/list-reduce/index.js +21 -0
  233. package/src/verblets/list-reduce/index.spec.js +27 -0
  234. package/src/verblets/list-reduce/index.spec.jsx +27 -0
  235. package/src/verblets/name/README.md +15 -0
  236. package/src/verblets/name/index.examples.js +28 -0
  237. package/src/verblets/name/index.js +19 -0
  238. package/src/verblets/name/index.spec.js +33 -0
  239. package/src/verblets/name-similar-to/README.md +26 -0
  240. package/src/verblets/name-similar-to/index.examples.js +18 -0
  241. package/src/verblets/name-similar-to/index.js +20 -0
  242. package/src/verblets/name-similar-to/index.spec.js +13 -0
  243. package/src/verblets/number/index.examples.js +173 -7
  244. package/src/verblets/number/index.js +5 -2
  245. package/src/verblets/number/index.spec.js +1 -3
  246. package/src/verblets/number-with-units/index.examples.js +5 -1
  247. package/src/verblets/number-with-units/index.js +74 -9
  248. package/src/verblets/number-with-units/number-with-units-result.json +23 -0
  249. package/src/verblets/schema-org/index.examples.js +2 -7
  250. package/src/verblets/schema-org/index.js +32 -3
  251. package/src/verblets/sentiment/README.md +10 -0
  252. package/src/verblets/sentiment/index.examples.js +20 -0
  253. package/src/verblets/sentiment/index.js +9 -0
  254. package/src/verblets/sentiment/index.spec.js +20 -0
  255. package/src/verblets/to-object/index.js +10 -15
  256. package/src/verblets/to-object/index.spec.js +1 -4
  257. package/.eslintrc.json +0 -42
  258. package/docs/README.md +0 -41
  259. package/docs/babel.config.js +0 -3
  260. package/docs/blog/2019-05-28-first-blog-post.md +0 -12
  261. package/docs/blog/2019-05-29-long-blog-post.md +0 -44
  262. package/docs/blog/2021-08-01-mdx-blog-post.mdx +0 -20
  263. package/docs/blog/2021-08-26-welcome/docusaurus-plushie-banner.jpeg +0 -0
  264. package/docs/blog/2021-08-26-welcome/index.md +0 -25
  265. package/docs/blog/authors.yml +0 -17
  266. package/docs/docs/api/bool.md +0 -74
  267. package/docs/docs/api/search.md +0 -51
  268. package/docs/docs/intro.md +0 -47
  269. package/docs/docs/tutorial-basics/_category_.json +0 -8
  270. package/docs/docs/tutorial-basics/congratulations.md +0 -23
  271. package/docs/docs/tutorial-basics/create-a-blog-post.md +0 -34
  272. package/docs/docs/tutorial-basics/create-a-document.md +0 -57
  273. package/docs/docs/tutorial-basics/create-a-page.md +0 -43
  274. package/docs/docs/tutorial-basics/deploy-your-site.md +0 -31
  275. package/docs/docs/tutorial-basics/markdown-features.mdx +0 -152
  276. package/docs/docs/tutorial-extras/_category_.json +0 -7
  277. package/docs/docs/tutorial-extras/img/docsVersionDropdown.png +0 -0
  278. package/docs/docs/tutorial-extras/img/localeDropdown.png +0 -0
  279. package/docs/docs/tutorial-extras/manage-docs-versions.md +0 -55
  280. package/docs/docs/tutorial-extras/translate-your-site.md +0 -88
  281. package/docs/docusaurus.config.js +0 -120
  282. package/docs/package.json +0 -44
  283. package/docs/sidebars.js +0 -31
  284. package/docs/src/components/HomepageFeatures/index.js +0 -61
  285. package/docs/src/components/HomepageFeatures/styles.module.css +0 -11
  286. package/docs/src/css/custom.css +0 -30
  287. package/docs/src/pages/index.js +0 -43
  288. package/docs/src/pages/index.module.css +0 -23
  289. package/docs/src/pages/markdown-page.md +0 -7
  290. package/docs/static/.nojekyll +0 -0
  291. package/docs/static/img/docusaurus-social-card.jpg +0 -0
  292. package/docs/static/img/docusaurus.png +0 -0
  293. package/docs/static/img/favicon.ico +0 -0
  294. package/docs/static/img/logo.svg +0 -1
  295. package/docs/static/img/undraw_docusaurus_mountain.svg +0 -171
  296. package/docs/static/img/undraw_docusaurus_react.svg +0 -170
  297. package/docs/static/img/undraw_docusaurus_tree.svg +0 -40
  298. package/src/constants/openai.js +0 -65
  299. /package/{.vite.config.examples.js → .vitest.config.examples.js} +0 -0
  300. /package/{.vite.config.js → .vitest.config.js} +0 -0
@@ -6,9 +6,8 @@ vi.mock('../../lib/chatgpt/index.js', () => ({
6
6
  default: vi.fn().mockImplementation((text) => {
7
7
  if (/prompt text to match/.test(text)) {
8
8
  return 'True';
9
- } else {
10
- return 'undefined';
11
9
  }
10
+ return 'undefined';
12
11
  }),
13
12
  }));
14
13
 
@@ -16,8 +15,8 @@ const examples = [
16
15
  {
17
16
  name: 'Basic usage',
18
17
  inputs: { text: 'test' },
19
- want: { result: true }
20
- }
18
+ want: { result: true },
19
+ },
21
20
  ];
22
21
 
23
22
  describe('Auto verblet', () => {
@@ -26,8 +25,7 @@ describe('Auto verblet', () => {
26
25
  const result = await auto(example.inputs.text);
27
26
 
28
27
  if (example.want.typeOfResult) {
29
- expect(typeof result)
30
- .toStrictEqual(example.want.typeOfResult);
28
+ expect(typeof result).toStrictEqual(example.want.typeOfResult);
31
29
  }
32
30
  });
33
31
  });
@@ -0,0 +1,36 @@
1
+ # bool
2
+
3
+ Interpret natural language questions as yes/no decisions and return a boolean.
4
+ The verblet uses ChatGPT to reason about the provided text and responds with
5
+ `true` or `false`.
6
+
7
+ ```javascript
8
+ import bool from './index.js';
9
+
10
+ const result = await bool('Does Mace Windu have a purple lightsaber?');
11
+ // result === true
12
+ ```
13
+
14
+ ## Use case: deployment gate
15
+
16
+ You can feed dynamic context to `bool` to make policy decisions. Combine local
17
+ variables with text to create nuanced yes/no prompts that a large language model
18
+ can reason about:
19
+
20
+ ```javascript
21
+ const filesChanged = 3;
22
+ const testsPassing = 247;
23
+ const isFriday = true;
24
+
25
+ const shouldDeploy = await bool(`
26
+ It's ${isFriday ? 'Friday' : 'a weekday'} at 4:45 PM.
27
+ ${filesChanged} files changed and all ${testsPassing} tests are passing.
28
+ The deployment window closes at 5 PM. Should we deploy to production?
29
+ `);
30
+
31
+ console.log(shouldDeploy);
32
+ // => false (A cautious answer based on the context)
33
+ ```
34
+
35
+ This approach enables policy checks and decision gates that rely on natural
36
+ language reasoning rather than hard‑coded rules.
@@ -1,6 +1,7 @@
1
- import { describe, expect, it } from 'vitest';
1
+ import { describe, expect, it, beforeAll, afterAll } from 'vitest';
2
2
 
3
3
  import bool from './index.js';
4
+ import aiExpect from '../expect/index.js';
4
5
  import { longTestTimeout } from '../../constants/common.js';
5
6
 
6
7
  const examples = [
@@ -15,14 +16,65 @@ const examples = [
15
16
  ];
16
17
 
17
18
  describe('Bool verblet', () => {
19
+ // Set environment mode to 'none' for all tests to avoid throwing
20
+ const originalMode = process.env.LLM_EXPECT_MODE;
21
+
22
+ beforeAll(() => {
23
+ process.env.LLM_EXPECT_MODE = 'none';
24
+ });
25
+
26
+ afterAll(() => {
27
+ if (originalMode !== undefined) {
28
+ process.env.LLM_EXPECT_MODE = originalMode;
29
+ } else {
30
+ delete process.env.LLM_EXPECT_MODE;
31
+ }
32
+ });
33
+
18
34
  examples.forEach((example) => {
19
35
  it(
20
36
  `${example.inputs.text}`,
21
37
  async () => {
22
38
  const result = await bool(example.inputs.text);
23
39
  expect(result).toStrictEqual(example.want.result);
40
+
41
+ // Additional LLM assertion to validate the boolean result makes sense
42
+ const resultMakesSense = await aiExpect({
43
+ question: example.inputs.text,
44
+ answer: result,
45
+ }).toSatisfy('Is this a reasonable yes/no answer to a Star Wars question?');
46
+ expect(resultMakesSense).toBe(true);
24
47
  },
25
48
  longTestTimeout
26
49
  );
27
50
  });
51
+
52
+ it(
53
+ 'should handle complex contextual decisions',
54
+ async () => {
55
+ const complexQuestion = `
56
+ Given the context: It's Friday at 4:45 PM, we have 3 files changed (150+ lines, 20- lines),
57
+ all 247 tests are passing, and the deployment window closes at 5 PM.
58
+ Should we deploy this change to production?
59
+ `;
60
+
61
+ const result = await bool(complexQuestion);
62
+
63
+ // Traditional assertion
64
+ expect(typeof result).toBe('boolean');
65
+
66
+ // LLM assertion to validate the decision reasoning
67
+ const decisionIsReasonable = await aiExpect(
68
+ `The question was about Friday afternoon deployment with passing tests. The decision was: ${result}`
69
+ ).toSatisfy('Does this sound like a reasonable deployment decision?');
70
+ expect(decisionIsReasonable).toBe(true);
71
+
72
+ // Additional assertion about the decision being conservative
73
+ const isConservativeDecision = await aiExpect(
74
+ `A boolean decision of ${result} for Friday afternoon deployment`
75
+ ).toSatisfy('Is this a cautious approach to deployment timing?');
76
+ expect(isConservativeDecision).toBe(true);
77
+ },
78
+ longTestTimeout
79
+ );
28
80
  });
@@ -3,23 +3,20 @@ import stripResponse from '../../lib/strip-response/index.js';
3
3
  import toBool from '../../lib/to-bool/index.js';
4
4
  import { constants as promptConstants } from '../../prompts/index.js';
5
5
 
6
- const {
7
- asBool,
8
- asUndefinedByDefault,
9
- contentIsQuestion,
10
- explainAndSeparate,
11
- explainAndSeparatePrimitive,
12
- } = promptConstants;
6
+ const { asBool, asUndefinedByDefault, explainAndSeparate, explainAndSeparatePrimitive } =
7
+ promptConstants;
13
8
 
14
- export default async (text, options={}) => {
9
+ export default async (text, config = {}) => {
10
+ const { llm, ...options } = config;
15
11
  const systemPrompt = `
16
12
  ${explainAndSeparate} ${explainAndSeparatePrimitive}
17
13
 
18
14
  ${asBool} ${asUndefinedByDefault}
19
- `
15
+ `;
20
16
  const response = await chatGPT(text, {
21
17
  modelOptions: {
22
18
  systemPrompt,
19
+ ...llm,
23
20
  },
24
21
  ...options,
25
22
  });
@@ -27,9 +27,7 @@ const examples = [
27
27
  describe('bool verblet', () => {
28
28
  examples.forEach((example) => {
29
29
  it(example.name, async () => {
30
- expect(await bool(example.inputs.text)).toStrictEqual(
31
- example.want.result
32
- );
30
+ expect(await bool(example.inputs.text)).toStrictEqual(example.want.result);
33
31
  });
34
32
  });
35
33
  });
@@ -0,0 +1,166 @@
1
+ # Central Tendency Verblet
2
+
3
+ A cognitive science-based function for evaluating how central or prototypical an item is within a category. Based on prototype theory and family resemblance principles from cognitive psychology.
4
+
5
+ ## Overview
6
+
7
+ The `centralTendency` verblet assesses graded typicality by analyzing feature overlap, core characteristics, and functional alignment with seed items. It implements cognitive science principles to provide nuanced category membership evaluation beyond simple binary classification.
8
+
9
+ ## Cognitive Science Foundations
10
+
11
+ ### Prototype Theory
12
+ Categories have graded structure with central (prototypical) and peripheral members. Some items are better examples of a category than others.
13
+
14
+ ### Family Resemblance
15
+ Category members share overlapping features without requiring identical characteristics. Items can belong to a category through different combinations of shared features.
16
+
17
+ ### Graded Typicality
18
+ Membership exists on a continuum from highly typical (central) to atypical (peripheral) rather than binary in/out classification.
19
+
20
+ ## Basic Usage
21
+
22
+ ```javascript
23
+ import { centralTendency } from './index.js';
24
+
25
+ // Evaluate bird centrality
26
+ const birdSeeds = ['robin', 'sparrow', 'bluejay', 'cardinal'];
27
+ const config = {
28
+ context: 'Evaluate based on typical bird characteristics and behavior',
29
+ coreFeatures: ['feathers', 'beak', 'lays eggs'],
30
+ llm: 'fastGoodCheap'
31
+ };
32
+
33
+ const result = await centralTendency('robin', birdSeeds, config);
34
+ // Returns: { score: 0.92, reason: "Robin exemplifies core bird features...", confidence: 0.88 }
35
+
36
+ const penguinResult = await centralTendency('penguin', birdSeeds, config);
37
+ // Returns: { score: 0.65, reason: "Penguin is a bird but lacks flight...", confidence: 0.82 }
38
+ ```
39
+
40
+ ## Advanced Features
41
+
42
+ ### Sample Generation
43
+ Generate representative category examples:
44
+
45
+ ```javascript
46
+ import categorySamples from '../../chains/category-samples/index.js';
47
+
48
+ const animalSamples = await categorySamples('animal', {
49
+ context: 'Diverse animal kingdom representation across phyla',
50
+ count: 6,
51
+ diversityLevel: 'high', // 'high', 'balanced', or 'focused'
52
+ llm: 'fastGoodCheap'
53
+ });
54
+ // Returns: ['dog', 'eagle', 'salmon', 'butterfly', 'octopus', 'frog']
55
+ ```
56
+
57
+ ### Bulk Processing
58
+ Evaluate multiple items efficiently:
59
+
60
+ ```javascript
61
+ import { bulkCentralTendency } from './index.js';
62
+
63
+ const testAnimals = ['wolf', 'tiger', 'elephant', 'whale'];
64
+ const mammalSeeds = ['dog', 'cat', 'horse', 'cow'];
65
+
66
+ const results = await bulkCentralTendency(
67
+ testAnimals,
68
+ mammalSeeds,
69
+ {
70
+ context: 'Mammalian characteristics and traits',
71
+ coreFeatures: ['warm-blooded', 'hair/fur', 'mammary glands'],
72
+ llm: 'fastGoodCheap',
73
+ chunkSize: 3,
74
+ maxAttempts: 2
75
+ }
76
+ );
77
+ ```
78
+
79
+ ## Parameters
80
+
81
+ ### centralTendency(item, seedItems, config)
82
+
83
+ - **item** (string): The item to evaluate for centrality
84
+ - **seedItems** (string[]): Array of known category members for comparison
85
+ - **config** (Object): Configuration options
86
+ - **context** (string): Context description for evaluation (default: '')
87
+ - **coreFeatures** (string[]): Known core/definitional features of the category (default: [])
88
+ - **llm** (string): LLM model to use (default: 'fastGoodCheap')
89
+
90
+ ### categorySamples(categoryName, config)
91
+
92
+ - **categoryName** (string): Name of the category
93
+ - **config** (Object): Configuration options
94
+ - **context** (string): Context for seed generation (default: '')
95
+ - **count** (number): Number of seed items to generate (default: 8)
96
+ - **diversityLevel** (string): 'high', 'balanced', or 'focused' (default: 'balanced')
97
+ - **llm** (string): LLM model to use (default: 'fastGoodCheap')
98
+
99
+ ## Return Values
100
+
101
+ ### centralTendency Result
102
+ ```javascript
103
+ {
104
+ score: 0.85, // Centrality score (0.0-1.0)
105
+ reason: "...", // Brief explanation of assessment
106
+ confidence: 0.82 // Confidence in assessment (0.0-1.0)
107
+ }
108
+ ```
109
+
110
+ ## Cognitive Science Applications
111
+
112
+ ### Natural vs Artifact Categories
113
+ ```javascript
114
+ // Natural categories often have clearer prototypes
115
+ const fruitConfig = {
116
+ context: 'Botanical fruit classification based on plant biology',
117
+ coreFeatures: ['seed-bearing', 'develops from flower']
118
+ };
119
+
120
+ // Artifact categories may be more functionally defined
121
+ const toolConfig = {
122
+ context: 'Hand tools for mechanical work and construction',
123
+ coreFeatures: ['handheld', 'mechanical advantage']
124
+ };
125
+ ```
126
+
127
+ ### Context Effects on Categorization
128
+ ```javascript
129
+ // Same item, different contexts
130
+ const classicalConfig = {
131
+ context: 'Classical orchestral instruments for formal concerts',
132
+ coreFeatures: ['acoustic', 'complex technique', 'wide range']
133
+ };
134
+
135
+ const folkConfig = {
136
+ context: 'Portable folk instruments for informal music',
137
+ coreFeatures: ['portable', 'easy to learn', 'expressive']
138
+ };
139
+
140
+ // Harmonica will score differently in each context
141
+ ```
142
+
143
+ ### Category Types
144
+ The verblet works best with:
145
+ - **Natural categories**: Birds, mammals, fruits, minerals
146
+ - **Artifact categories**: Tools, vehicles, furniture, instruments
147
+ - **Activity categories**: Sports, games, professions, hobbies
148
+ - **Abstract categories**: Emotions, concepts, relationships
149
+
150
+ Note: Avoid arbitrary collections (e.g., "things in my room") as these lack the coherent structure that prototype theory describes.
151
+
152
+ ## Integration with Concept Science Chains
153
+
154
+ The `centralTendency` verblet integrates seamlessly with other concept science tools:
155
+
156
+ ```javascript
157
+ // Generate seeds, then evaluate centrality
158
+ const seeds = await categorySamples('vehicle', { context: 'Land transportation' });
159
+ const centrality = await centralTendency('bicycle', seeds, { context: 'Personal transportation' });
160
+
161
+ // Use in concept hierarchies
162
+ const superordinateSeeds = await categorySamples('animal');
163
+ const basicLevelSeeds = await categorySamples('bird');
164
+ const subordinateResult = await centralTendency('robin', basicLevelSeeds);
165
+ ```
166
+
@@ -0,0 +1,24 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "type": "object",
4
+ "additionalProperties": false,
5
+ "properties": {
6
+ "score": {
7
+ "type": "number",
8
+ "minimum": 0,
9
+ "maximum": 1,
10
+ "description": "Centrality score from 0.0 (peripheral) to 1.0 (prototypical)"
11
+ },
12
+ "reason": {
13
+ "type": "string",
14
+ "description": "Brief explanation of centrality assessment"
15
+ },
16
+ "confidence": {
17
+ "type": "number",
18
+ "minimum": 0,
19
+ "maximum": 1,
20
+ "description": "Confidence in this assessment"
21
+ }
22
+ },
23
+ "required": ["score", "reason", "confidence"]
24
+ }
@@ -0,0 +1,196 @@
1
+ /**
2
+ * Examples for centralTendency verblet
3
+ * Demonstrates cognitive science applications in prototype theory and graded typicality
4
+ */
5
+
6
+ import { describe, expect, it } from 'vitest';
7
+ import centralTendency from './index.js';
8
+ import categorySamples from '../../chains/category-samples/index.js';
9
+ import bulkCentralTendency from '../../chains/bulk-central-tendency/index.js';
10
+ import { longTestTimeout } from '../../constants/common.js';
11
+
12
+ describe('centralTendency examples', () => {
13
+ it(
14
+ 'evaluates bird centrality with new config format',
15
+ async () => {
16
+ const birdSeeds = ['robin', 'sparrow', 'bluejay', 'cardinal'];
17
+
18
+ const config = {
19
+ context: 'Evaluate based on typical bird characteristics and behavior',
20
+ coreFeatures: ['feathers', 'beak', 'lays eggs', 'flight'],
21
+ };
22
+
23
+ // Test prototypical bird
24
+ const robinResult = await centralTendency('robin', birdSeeds, config);
25
+ expect(robinResult).toHaveProperty('score');
26
+ expect(robinResult).toHaveProperty('reason');
27
+ expect(robinResult).toHaveProperty('confidence');
28
+ expect(robinResult.score).toBeGreaterThanOrEqual(0.7); // Should be high centrality
29
+
30
+ // Test atypical but valid bird
31
+ const penguinResult = await centralTendency('penguin', birdSeeds, config);
32
+ expect(penguinResult.score).toBeGreaterThan(0.3);
33
+ expect(penguinResult.score).toBeLessThan(robinResult.score); // Should be lower than robin
34
+
35
+ // Test non-bird that flies
36
+ const batResult = await centralTendency('bat', birdSeeds, config);
37
+ expect(batResult.score).toBeLessThan(0.4); // Should be low centrality
38
+ },
39
+ longTestTimeout
40
+ );
41
+
42
+ it(
43
+ 'compares natural vs artifact categories with fruit example',
44
+ async () => {
45
+ const fruitSeeds = ['apple', 'orange', 'banana', 'grape'];
46
+
47
+ // Biological/botanical context
48
+ const botanicalConfig = {
49
+ context: 'Judge by botanical definition and structure',
50
+ coreFeatures: ['seed-bearing', 'develops from flower', 'fleshy pericarp'],
51
+ };
52
+
53
+ // Culinary/folk context
54
+ const culinaryConfig = {
55
+ context: 'Judge by culinary use and folk categorization',
56
+ coreFeatures: ['sweet taste', 'eaten fresh', 'dessert-like'],
57
+ };
58
+
59
+ const botanicalResult = await centralTendency('tomato', fruitSeeds, botanicalConfig);
60
+ const culinaryResult = await centralTendency('tomato', fruitSeeds, culinaryConfig);
61
+
62
+ expect(botanicalResult.score).toBeGreaterThan(culinaryResult.score);
63
+ },
64
+ longTestTimeout
65
+ );
66
+
67
+ it(
68
+ 'evaluates tool centrality with core features',
69
+ async () => {
70
+ const toolSeeds = ['hammer', 'screwdriver', 'wrench', 'pliers'];
71
+
72
+ const config = {
73
+ context: 'Hand tools for mechanical work and construction',
74
+ coreFeatures: ['handheld', 'mechanical advantage', 'durable materials'],
75
+ };
76
+
77
+ const drillResult = await centralTendency('drill', toolSeeds, config);
78
+ const computerResult = await centralTendency('computer', toolSeeds, config);
79
+
80
+ expect(drillResult.score).toBeGreaterThan(computerResult.score);
81
+ expect(drillResult.score).toBeGreaterThanOrEqual(0.6); // Drill should be high (allow boundary)
82
+ expect(computerResult.score).toBeLessThan(0.5); // Computer should be low
83
+ },
84
+ longTestTimeout
85
+ );
86
+
87
+ it(
88
+ 'generates seeds with different diversity levels',
89
+ async () => {
90
+ // High diversity seeds
91
+ const highDiversitySeeds = await categorySamples('animal', {
92
+ context: 'Diverse animal kingdom representation across phyla',
93
+ count: 6,
94
+ diversityLevel: 'high',
95
+ });
96
+
97
+ expect(Array.isArray(highDiversitySeeds)).toBe(true);
98
+ expect(highDiversitySeeds.length).toBeGreaterThan(0);
99
+ expect(highDiversitySeeds.length).toBeLessThanOrEqual(6);
100
+
101
+ // Focused seeds
102
+ const focusedSeeds = await categorySamples('bird', {
103
+ context: 'Common backyard birds',
104
+ count: 5,
105
+ diversityLevel: 'focused',
106
+ });
107
+
108
+ expect(Array.isArray(focusedSeeds)).toBe(true);
109
+ expect(focusedSeeds.length).toBeGreaterThan(0);
110
+ },
111
+ longTestTimeout
112
+ );
113
+
114
+ it(
115
+ 'processes bulk items with error handling',
116
+ async () => {
117
+ const mammalSeeds = ['dog', 'cat', 'horse', 'cow'];
118
+ const testAnimals = ['wolf', 'tiger', 'elephant', 'whale', 'bat'];
119
+
120
+ const config = {
121
+ context: 'Mammalian characteristics and traits',
122
+ coreFeatures: ['warm-blooded', 'hair/fur', 'mammary glands', 'live birth'],
123
+ chunkSize: 3,
124
+ maxAttempts: 2,
125
+ };
126
+
127
+ const results = await bulkCentralTendency(testAnimals, mammalSeeds, config);
128
+
129
+ expect(results).toHaveLength(testAnimals.length);
130
+
131
+ // Check that most results are valid
132
+ const validResults = results.filter((r) => r !== undefined);
133
+ expect(validResults.length).toBeGreaterThan(testAnimals.length * 0.6);
134
+
135
+ // Validate structure of valid results
136
+ validResults.forEach((result) => {
137
+ expect(result).toHaveProperty('score');
138
+ expect(result).toHaveProperty('reason');
139
+ expect(result).toHaveProperty('confidence');
140
+ expect(result.score).toBeGreaterThanOrEqual(0);
141
+ expect(result.score).toBeLessThanOrEqual(1);
142
+ });
143
+ },
144
+ longTestTimeout
145
+ );
146
+
147
+ it(
148
+ 'demonstrates graded typicality in sports',
149
+ async () => {
150
+ const sportsSeeds = ['basketball', 'football', 'tennis', 'swimming'];
151
+
152
+ const config = {
153
+ context: 'Competitive physical activities with rules and scoring',
154
+ coreFeatures: ['rules', 'competition', 'physical skill', 'scoring'],
155
+ };
156
+
157
+ const soccerResult = await centralTendency('soccer', sportsSeeds, config);
158
+ const chessResult = await centralTendency('chess', sportsSeeds, config);
159
+ const videoGamesResult = await centralTendency('video games', sportsSeeds, config);
160
+
161
+ // Expect graded typicality: soccer should be more central than chess for physical sports
162
+ expect(soccerResult.score).toBeGreaterThan(chessResult.score);
163
+ // All results should be valid scores
164
+ expect(chessResult.score).toBeGreaterThanOrEqual(0);
165
+ expect(videoGamesResult.score).toBeGreaterThanOrEqual(0);
166
+ },
167
+ longTestTimeout
168
+ );
169
+
170
+ it(
171
+ 'demonstrates context steering effects',
172
+ async () => {
173
+ const musicSeeds = ['piano', 'guitar', 'violin', 'drums'];
174
+ const testItem = 'harmonica';
175
+
176
+ // Traditional/classical music context
177
+ const classicalConfig = {
178
+ context: 'Classical and orchestral instruments for formal concerts',
179
+ coreFeatures: ['acoustic', 'complex technique', 'wide range'],
180
+ };
181
+
182
+ // Folk/portable music context
183
+ const folkConfig = {
184
+ context: 'Portable folk and street instruments',
185
+ coreFeatures: ['portable', 'easy to learn', 'expressive'],
186
+ };
187
+
188
+ const classicalResult = await centralTendency(testItem, musicSeeds, classicalConfig);
189
+ const folkResult = await centralTendency(testItem, musicSeeds, folkConfig);
190
+
191
+ // Harmonica should score higher in folk context
192
+ expect(folkResult.score).toBeGreaterThan(classicalResult.score);
193
+ },
194
+ longTestTimeout
195
+ );
196
+ });