@far-world-labs/verblets 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (330) hide show
  1. package/README.md +98 -213
  2. package/dist/index.browser.js +221 -0
  3. package/dist/index.js +696 -0
  4. package/dist/shared-CMgpfDG4.js +10714 -0
  5. package/package.json +38 -15
  6. package/.cursor/launch.json +0 -30
  7. package/.cursor/settings.json +0 -20
  8. package/.github/workflows/branch-protection.yml +0 -22
  9. package/.github/workflows/ci.yml +0 -165
  10. package/.husky/pre-commit +0 -4
  11. package/.prettierrc +0 -6
  12. package/.release-it.json +0 -12
  13. package/.vitest.config.examples.js +0 -12
  14. package/.vitest.config.js +0 -8
  15. package/.vscode/launch.json +0 -31
  16. package/AGENTS.md +0 -220
  17. package/DEVELOPING.md +0 -105
  18. package/docker-compose.yml +0 -7
  19. package/eslint.config.js +0 -80
  20. package/scripts/clear-redis.js +0 -74
  21. package/scripts/generate-chain/index.js +0 -111
  22. package/scripts/generate-lib/index.js +0 -68
  23. package/scripts/generate-test/index.js +0 -137
  24. package/scripts/generate-verblet/README.md +0 -17
  25. package/scripts/generate-verblet/index.js +0 -110
  26. package/scripts/run.sh +0 -15
  27. package/scripts/runner/index.js +0 -56
  28. package/scripts/simple-editor/README.md +0 -34
  29. package/scripts/simple-editor/index.js +0 -79
  30. package/scripts/summarize-files/index.js +0 -70
  31. package/src/chains/README.md +0 -30
  32. package/src/chains/anonymize/README.md +0 -21
  33. package/src/chains/anonymize/index.examples.js +0 -75
  34. package/src/chains/anonymize/index.js +0 -121
  35. package/src/chains/anonymize/index.spec.js +0 -78
  36. package/src/chains/bulk-central-tendency/index.examples.js +0 -138
  37. package/src/chains/bulk-central-tendency/index.js +0 -91
  38. package/src/chains/bulk-filter/README.md +0 -21
  39. package/src/chains/bulk-filter/index.examples.js +0 -22
  40. package/src/chains/bulk-filter/index.js +0 -58
  41. package/src/chains/bulk-filter/index.spec.js +0 -38
  42. package/src/chains/bulk-find/README.md +0 -16
  43. package/src/chains/bulk-find/index.examples.js +0 -20
  44. package/src/chains/bulk-find/index.js +0 -30
  45. package/src/chains/bulk-find/index.spec.js +0 -26
  46. package/src/chains/bulk-group/README.md +0 -23
  47. package/src/chains/bulk-group/index.examples.js +0 -18
  48. package/src/chains/bulk-group/index.js +0 -34
  49. package/src/chains/bulk-group/index.spec.js +0 -41
  50. package/src/chains/bulk-map/README.md +0 -43
  51. package/src/chains/bulk-map/index.examples.js +0 -17
  52. package/src/chains/bulk-map/index.js +0 -86
  53. package/src/chains/bulk-map/index.spec.js +0 -44
  54. package/src/chains/bulk-reduce/README.md +0 -12
  55. package/src/chains/bulk-reduce/index.examples.js +0 -15
  56. package/src/chains/bulk-reduce/index.js +0 -13
  57. package/src/chains/bulk-reduce/index.spec.js +0 -25
  58. package/src/chains/bulk-score/README.md +0 -16
  59. package/src/chains/bulk-score/bulk-score-result.json +0 -18
  60. package/src/chains/bulk-score/index.examples.js +0 -22
  61. package/src/chains/bulk-score/index.js +0 -133
  62. package/src/chains/bulk-score/index.spec.js +0 -30
  63. package/src/chains/category-samples/README.md +0 -61
  64. package/src/chains/category-samples/index.examples.js +0 -103
  65. package/src/chains/category-samples/index.js +0 -134
  66. package/src/chains/collect-terms/README.md +0 -12
  67. package/src/chains/collect-terms/index.examples.js +0 -16
  68. package/src/chains/collect-terms/index.js +0 -44
  69. package/src/chains/collect-terms/index.spec.js +0 -25
  70. package/src/chains/conversation/README.md +0 -26
  71. package/src/chains/conversation/index.examples.js +0 -398
  72. package/src/chains/conversation/index.js +0 -126
  73. package/src/chains/conversation/index.spec.js +0 -148
  74. package/src/chains/conversation/turn-policies.js +0 -93
  75. package/src/chains/conversation/turn-policies.md +0 -123
  76. package/src/chains/conversation/turn-policies.spec.js +0 -135
  77. package/src/chains/date/README.md +0 -12
  78. package/src/chains/date/index.examples.js +0 -47
  79. package/src/chains/date/index.js +0 -74
  80. package/src/chains/date/index.spec.js +0 -62
  81. package/src/chains/disambiguate/README.md +0 -22
  82. package/src/chains/disambiguate/disambiguate-meanings-result.json +0 -16
  83. package/src/chains/disambiguate/index.examples.js +0 -18
  84. package/src/chains/disambiguate/index.js +0 -92
  85. package/src/chains/disambiguate/index.spec.js +0 -25
  86. package/src/chains/dismantle/README.md +0 -67
  87. package/src/chains/dismantle/dismantle.examples.js +0 -27
  88. package/src/chains/dismantle/index.examples.js +0 -30
  89. package/src/chains/dismantle/index.js +0 -303
  90. package/src/chains/dismantle/index.spec.js +0 -32
  91. package/src/chains/expect/README.md +0 -171
  92. package/src/chains/expect/index.examples.js +0 -146
  93. package/src/chains/expect/index.js +0 -207
  94. package/src/chains/expect/index.spec.js +0 -324
  95. package/src/chains/filter-ambiguous/README.md +0 -11
  96. package/src/chains/filter-ambiguous/index.examples.js +0 -20
  97. package/src/chains/filter-ambiguous/index.js +0 -49
  98. package/src/chains/filter-ambiguous/index.spec.js +0 -31
  99. package/src/chains/glossary/README.md +0 -19
  100. package/src/chains/glossary/index.examples.js +0 -386
  101. package/src/chains/glossary/index.js +0 -75
  102. package/src/chains/glossary/index.spec.js +0 -19
  103. package/src/chains/intersections/README.md +0 -166
  104. package/src/chains/intersections/index.examples.js +0 -280
  105. package/src/chains/intersections/index.js +0 -218
  106. package/src/chains/intersections/intersection-result.json +0 -38
  107. package/src/chains/list/index.examples.js +0 -68
  108. package/src/chains/list/index.js +0 -214
  109. package/src/chains/list/index.spec.js +0 -67
  110. package/src/chains/list/list-result.json +0 -16
  111. package/src/chains/list/schema.json +0 -24
  112. package/src/chains/llm-logger/README.md +0 -366
  113. package/src/chains/llm-logger/index.js +0 -591
  114. package/src/chains/llm-logger/index.spec.js +0 -391
  115. package/src/chains/llm-logger/schema.json +0 -105
  116. package/src/chains/questions/index.examples.js +0 -69
  117. package/src/chains/questions/index.js +0 -135
  118. package/src/chains/questions/index.spec.js +0 -29
  119. package/src/chains/scan-js/index.js +0 -116
  120. package/src/chains/set-interval/README.md +0 -81
  121. package/src/chains/set-interval/index.examples.js +0 -64
  122. package/src/chains/set-interval/index.js +0 -152
  123. package/src/chains/set-interval/index.spec.js +0 -70
  124. package/src/chains/socratic/README.md +0 -17
  125. package/src/chains/socratic/index.js +0 -64
  126. package/src/chains/socratic/index.spec.js +0 -24
  127. package/src/chains/sort/index.examples.js +0 -36
  128. package/src/chains/sort/index.js +0 -163
  129. package/src/chains/sort/index.spec.js +0 -112
  130. package/src/chains/sort/sort-result.json +0 -16
  131. package/src/chains/summary-map/README.md +0 -41
  132. package/src/chains/summary-map/index.examples.js +0 -64
  133. package/src/chains/summary-map/index.js +0 -226
  134. package/src/chains/summary-map/index.spec.js +0 -153
  135. package/src/chains/test/index.js +0 -114
  136. package/src/chains/test-advice/index.js +0 -35
  137. package/src/chains/themes/README.md +0 -20
  138. package/src/chains/themes/index.examples.js +0 -17
  139. package/src/chains/themes/index.js +0 -28
  140. package/src/chains/themes/index.spec.js +0 -19
  141. package/src/chains/veiled-variants/index.examples.js +0 -18
  142. package/src/chains/veiled-variants/index.js +0 -107
  143. package/src/chains/veiled-variants/index.spec.js +0 -40
  144. package/src/constants/common.js +0 -13
  145. package/src/constants/messages.js +0 -3
  146. package/src/constants/models.js +0 -184
  147. package/src/index.js +0 -203
  148. package/src/json-schemas/README.md +0 -13
  149. package/src/json-schemas/cars-test.json +0 -11
  150. package/src/json-schemas/index.js +0 -12
  151. package/src/json-schemas/intent.json +0 -38
  152. package/src/json-schemas/schema-dot-org-photograph.json +0 -133
  153. package/src/json-schemas/schema-dot-org-place.json +0 -129
  154. package/src/lib/README.md +0 -26
  155. package/src/lib/any-signal/index.js +0 -28
  156. package/src/lib/assert/README.md +0 -84
  157. package/src/lib/assert/index.js +0 -50
  158. package/src/lib/bulk-filter/README.md +0 -22
  159. package/src/lib/bulk-filter/index.examples.js +0 -27
  160. package/src/lib/bulk-filter/index.js +0 -63
  161. package/src/lib/bulk-filter/index.spec.js +0 -38
  162. package/src/lib/bulk-find/README.md +0 -18
  163. package/src/lib/bulk-find/index.examples.js +0 -19
  164. package/src/lib/bulk-find/index.js +0 -30
  165. package/src/lib/bulk-find/index.spec.js +0 -41
  166. package/src/lib/chatgpt/index.js +0 -163
  167. package/src/lib/combinations/index.js +0 -30
  168. package/src/lib/combinations/index.spec.js +0 -23
  169. package/src/lib/editor/index.js +0 -31
  170. package/src/lib/functional/index.js +0 -28
  171. package/src/lib/logger-service/index.js +0 -32
  172. package/src/lib/parse-js-parts/index.js +0 -321
  173. package/src/lib/parse-js-parts/index.spec.js +0 -156
  174. package/src/lib/parse-llm-list/README.md +0 -39
  175. package/src/lib/parse-llm-list/index.js +0 -54
  176. package/src/lib/parse-llm-list/index.spec.js +0 -59
  177. package/src/lib/path-aliases/index.js +0 -37
  178. package/src/lib/path-aliases/index.spec.js +0 -64
  179. package/src/lib/pave/index.js +0 -34
  180. package/src/lib/pave/index.spec.js +0 -76
  181. package/src/lib/prompt-cache/index.js +0 -50
  182. package/src/lib/retry/index.js +0 -66
  183. package/src/lib/retry/index.spec.js +0 -86
  184. package/src/lib/ring-buffer/README.md +0 -82
  185. package/src/lib/ring-buffer/index.js +0 -235
  186. package/src/lib/ring-buffer/index.spec.js +0 -388
  187. package/src/lib/search-best-first/city-walk.spec.js +0 -37
  188. package/src/lib/search-best-first/index.js +0 -97
  189. package/src/lib/search-best-first/index.spec.js +0 -35
  190. package/src/lib/search-js-files/code-features-property-definitions.json +0 -123
  191. package/src/lib/search-js-files/index.examples.js +0 -22
  192. package/src/lib/search-js-files/index.js +0 -155
  193. package/src/lib/search-js-files/index.spec.js +0 -34
  194. package/src/lib/search-js-files/scan-file.js +0 -242
  195. package/src/lib/shorten-text/index.js +0 -25
  196. package/src/lib/shorten-text/index.spec.js +0 -68
  197. package/src/lib/strip-numeric/index.js +0 -5
  198. package/src/lib/strip-response/index.js +0 -30
  199. package/src/lib/template-replace/index.js +0 -23
  200. package/src/lib/template-replace/index.spec.js +0 -60
  201. package/src/lib/timed-abort-controller/index.js +0 -41
  202. package/src/lib/to-bool/index.js +0 -8
  203. package/src/lib/to-date/index.js +0 -11
  204. package/src/lib/to-enum/index.js +0 -14
  205. package/src/lib/to-number/index.js +0 -12
  206. package/src/lib/to-number-with-units/index.js +0 -51
  207. package/src/lib/transcribe/index.js +0 -78
  208. package/src/prompts/README.md +0 -17
  209. package/src/prompts/as-enum.js +0 -5
  210. package/src/prompts/as-json-schema.js +0 -9
  211. package/src/prompts/as-object-with-schema.js +0 -26
  212. package/src/prompts/as-schema-org-text.js +0 -25
  213. package/src/prompts/as-schema-org-type.js +0 -1
  214. package/src/prompts/blog-post.js +0 -7
  215. package/src/prompts/code-features.js +0 -24
  216. package/src/prompts/constants.js +0 -101
  217. package/src/prompts/features-json-schema.js +0 -27
  218. package/src/prompts/generate-collection.js +0 -26
  219. package/src/prompts/generate-list.js +0 -48
  220. package/src/prompts/generate-questions.js +0 -19
  221. package/src/prompts/index.js +0 -20
  222. package/src/prompts/intent.js +0 -60
  223. package/src/prompts/output-succinct-names.js +0 -3
  224. package/src/prompts/select-from-threshold.js +0 -17
  225. package/src/prompts/sort.js +0 -31
  226. package/src/prompts/style.js +0 -38
  227. package/src/prompts/summarize.js +0 -13
  228. package/src/prompts/token-budget.js +0 -3
  229. package/src/prompts/wrap-list.js +0 -11
  230. package/src/prompts/wrap-variable.js +0 -36
  231. package/src/services/llm-model/global-overrides.spec.js +0 -432
  232. package/src/services/llm-model/index.js +0 -308
  233. package/src/services/llm-model/model.js +0 -21
  234. package/src/services/llm-model/negotiate.spec.js +0 -447
  235. package/src/services/redis/index.js +0 -147
  236. package/src/test/setup.js +0 -20
  237. package/src/verblets/README.md +0 -26
  238. package/src/verblets/auto/index.examples.js +0 -31
  239. package/src/verblets/auto/index.js +0 -28
  240. package/src/verblets/auto/index.spec.js +0 -32
  241. package/src/verblets/bool/README.md +0 -36
  242. package/src/verblets/bool/index.examples.js +0 -80
  243. package/src/verblets/bool/index.js +0 -25
  244. package/src/verblets/bool/index.schema.json +0 -14
  245. package/src/verblets/bool/index.spec.js +0 -33
  246. package/src/verblets/central-tendency/README.md +0 -166
  247. package/src/verblets/central-tendency/central-tendency-result.json +0 -24
  248. package/src/verblets/central-tendency/index.examples.js +0 -196
  249. package/src/verblets/central-tendency/index.js +0 -171
  250. package/src/verblets/central-tendency/index.spec.js +0 -148
  251. package/src/verblets/conversation-turn/README.md +0 -33
  252. package/src/verblets/conversation-turn/index.examples.js +0 -218
  253. package/src/verblets/conversation-turn/index.js +0 -68
  254. package/src/verblets/conversation-turn/index.spec.js +0 -77
  255. package/src/verblets/conversation-turn-multi/README.md +0 -31
  256. package/src/verblets/conversation-turn-multi/index.examples.js +0 -160
  257. package/src/verblets/conversation-turn-multi/index.js +0 -104
  258. package/src/verblets/conversation-turn-multi/index.spec.js +0 -63
  259. package/src/verblets/enum/index.examples.js +0 -30
  260. package/src/verblets/enum/index.js +0 -18
  261. package/src/verblets/enum/index.spec.js +0 -35
  262. package/src/verblets/expect/README.md +0 -64
  263. package/src/verblets/expect/index.examples.js +0 -109
  264. package/src/verblets/expect/index.js +0 -75
  265. package/src/verblets/expect/index.spec.js +0 -127
  266. package/src/verblets/intent/index.examples.js +0 -139
  267. package/src/verblets/intent/index.js +0 -60
  268. package/src/verblets/intent/index.spec.js +0 -31
  269. package/src/verblets/intersection/README.md +0 -16
  270. package/src/verblets/intersection/index.examples.js +0 -89
  271. package/src/verblets/intersection/index.js +0 -125
  272. package/src/verblets/intersection/index.spec.js +0 -60
  273. package/src/verblets/intersection/intersection-result.json +0 -16
  274. package/src/verblets/list-expand/README.md +0 -10
  275. package/src/verblets/list-expand/index.examples.js +0 -14
  276. package/src/verblets/list-expand/index.js +0 -104
  277. package/src/verblets/list-expand/index.spec.js +0 -18
  278. package/src/verblets/list-expand/list-expand-result.json +0 -16
  279. package/src/verblets/list-filter/README.md +0 -22
  280. package/src/verblets/list-filter/index.examples.js +0 -26
  281. package/src/verblets/list-filter/index.js +0 -18
  282. package/src/verblets/list-filter/index.spec.js +0 -19
  283. package/src/verblets/list-find/README.md +0 -11
  284. package/src/verblets/list-find/index.examples.js +0 -15
  285. package/src/verblets/list-find/index.js +0 -17
  286. package/src/verblets/list-find/index.spec.js +0 -19
  287. package/src/verblets/list-group/README.md +0 -16
  288. package/src/verblets/list-group/index.examples.js +0 -16
  289. package/src/verblets/list-group/index.js +0 -112
  290. package/src/verblets/list-group/index.spec.js +0 -35
  291. package/src/verblets/list-group/list-group-result.json +0 -16
  292. package/src/verblets/list-map/README.md +0 -11
  293. package/src/verblets/list-map/index.examples.js +0 -15
  294. package/src/verblets/list-map/index.js +0 -26
  295. package/src/verblets/list-map/index.spec.js +0 -17
  296. package/src/verblets/list-reduce/README.md +0 -10
  297. package/src/verblets/list-reduce/index.examples.js +0 -14
  298. package/src/verblets/list-reduce/index.js +0 -21
  299. package/src/verblets/list-reduce/index.spec.js +0 -27
  300. package/src/verblets/list-reduce/index.spec.jsx +0 -27
  301. package/src/verblets/name/README.md +0 -15
  302. package/src/verblets/name/index.examples.js +0 -28
  303. package/src/verblets/name/index.js +0 -19
  304. package/src/verblets/name/index.spec.js +0 -33
  305. package/src/verblets/name-similar-to/README.md +0 -26
  306. package/src/verblets/name-similar-to/index.examples.js +0 -18
  307. package/src/verblets/name-similar-to/index.js +0 -20
  308. package/src/verblets/name-similar-to/index.spec.js +0 -13
  309. package/src/verblets/number/index.examples.js +0 -199
  310. package/src/verblets/number/index.js +0 -25
  311. package/src/verblets/number/index.spec.js +0 -33
  312. package/src/verblets/number-with-units/index.examples.js +0 -38
  313. package/src/verblets/number-with-units/index.js +0 -84
  314. package/src/verblets/number-with-units/index.spec.js +0 -46
  315. package/src/verblets/number-with-units/number-with-units-result.json +0 -23
  316. package/src/verblets/people-list/README.md +0 -28
  317. package/src/verblets/people-list/index.examples.js +0 -184
  318. package/src/verblets/people-list/index.js +0 -44
  319. package/src/verblets/people-list/index.spec.js +0 -49
  320. package/src/verblets/schema-org/index.examples.js +0 -51
  321. package/src/verblets/schema-org/index.js +0 -37
  322. package/src/verblets/schema-org/index.spec.js +0 -39
  323. package/src/verblets/sentiment/README.md +0 -10
  324. package/src/verblets/sentiment/index.examples.js +0 -20
  325. package/src/verblets/sentiment/index.js +0 -9
  326. package/src/verblets/sentiment/index.spec.js +0 -20
  327. package/src/verblets/to-object/README.md +0 -38
  328. package/src/verblets/to-object/index.examples.js +0 -29
  329. package/src/verblets/to-object/index.js +0 -131
  330. package/src/verblets/to-object/index.spec.js +0 -71
@@ -1,447 +0,0 @@
1
- import { beforeEach, describe, expect, it } from 'vitest';
2
- import modelService from './index.js';
3
- import Model from './model.js';
4
-
5
- // helper tokenizer
6
- const tokenizer = (t) => t.split(' ');
7
-
8
- describe('Model negotiation', () => {
9
- beforeEach(() => {
10
- // Reset models before each test
11
- modelService.models = {};
12
- modelService.bestPublicModelKey = 'fastGood';
13
- });
14
-
15
- describe('Privacy models', () => {
16
- it('prefers privacy model when requested and available', () => {
17
- modelService.models = {
18
- privacy: new Model({
19
- name: 'privacy-model',
20
- maxContextWindow: 128000,
21
- maxOutputTokens: 8192,
22
- requestTimeout: 1000,
23
- tokenizer,
24
- }),
25
- fastGood: new Model({
26
- name: 'fast-good-model',
27
- maxContextWindow: 128000,
28
- maxOutputTokens: 16384,
29
- requestTimeout: 1000,
30
- tokenizer,
31
- }),
32
- };
33
-
34
- const key = modelService.negotiateModel('fastGood', { privacy: true });
35
- expect(key).toBe('privacy');
36
- });
37
-
38
- it('throws error when privacy requested but not configured', () => {
39
- modelService.models = {
40
- fastGood: new Model({
41
- name: 'fast-good-model',
42
- maxContextWindow: 128000,
43
- maxOutputTokens: 16384,
44
- requestTimeout: 1000,
45
- tokenizer,
46
- }),
47
- };
48
-
49
- expect(modelService.negotiateModel('fastGood', { privacy: true })).toBe(undefined);
50
- });
51
- });
52
-
53
- describe('Exact model key matching', () => {
54
- beforeEach(() => {
55
- modelService.models = {
56
- fastGood: new Model({
57
- name: 'fast-good',
58
- maxContextWindow: 128000,
59
- maxOutputTokens: 16384,
60
- requestTimeout: 1000,
61
- tokenizer,
62
- }),
63
- fastCheap: new Model({
64
- name: 'fast-cheap',
65
- maxContextWindow: 128000,
66
- maxOutputTokens: 8192,
67
- requestTimeout: 1000,
68
- tokenizer,
69
- }),
70
- fastReasoning: new Model({
71
- name: 'fast-reasoning',
72
- maxContextWindow: 200000,
73
- maxOutputTokens: 100000,
74
- requestTimeout: 1000,
75
- tokenizer,
76
- }),
77
- fastCheapReasoning: new Model({
78
- name: 'fast-cheap-reasoning',
79
- maxContextWindow: 128000,
80
- maxOutputTokens: 16384,
81
- requestTimeout: 1000,
82
- tokenizer,
83
- }),
84
- fastGoodMulti: new Model({
85
- name: 'fast-good-multi',
86
- maxContextWindow: 1000000,
87
- maxOutputTokens: 32768,
88
- requestTimeout: 1000,
89
- tokenizer,
90
- }),
91
- fastCheapReasoningMulti: new Model({
92
- name: 'fast-cheap-reasoning-multi',
93
- maxContextWindow: 128000,
94
- maxOutputTokens: 16384,
95
- requestTimeout: 1000,
96
- tokenizer,
97
- }),
98
- good: new Model({
99
- name: 'good',
100
- maxContextWindow: 128000,
101
- maxOutputTokens: 16384,
102
- requestTimeout: 1000,
103
- tokenizer,
104
- }),
105
- reasoning: new Model({
106
- name: 'reasoning',
107
- maxContextWindow: 200000,
108
- maxOutputTokens: 100000,
109
- requestTimeout: 1000,
110
- tokenizer,
111
- }),
112
- fast: new Model({
113
- name: 'fast',
114
- maxContextWindow: 128000,
115
- maxOutputTokens: 16384,
116
- requestTimeout: 1000,
117
- tokenizer,
118
- }),
119
- cheap: new Model({
120
- name: 'cheap',
121
- maxContextWindow: 128000,
122
- maxOutputTokens: 8192,
123
- requestTimeout: 1000,
124
- tokenizer,
125
- }),
126
- };
127
- });
128
-
129
- it('returns highest priority match for fast + cheap', () => {
130
- // Should find fastCheap since it has both fast and cheap
131
- const key = modelService.negotiateModel(null, { fast: true, cheap: true });
132
- expect(key).toBe('fastCheap'); // fastCheap matches both requirements
133
- });
134
-
135
- it('returns highest priority match for fast + reasoning', () => {
136
- // Should find fastReasoning since it has both fast and reasoning
137
- const key = modelService.negotiateModel(null, { fast: true, reasoning: true });
138
- expect(key).toBe('fastCheapReasoning'); // fastReasoning matches both requirements
139
- });
140
-
141
- it('returns exact match when it exists and has high priority', () => {
142
- const key = modelService.negotiateModel(null, { fast: true, cheap: true, reasoning: true });
143
- expect(key).toBe('fastCheapReasoning'); // Exact match exists
144
- });
145
-
146
- it('returns exact match for fast + good + multi', () => {
147
- const key = modelService.negotiateModel(null, { fast: true, good: true, multi: true });
148
- expect(key).toBe('fastGoodMulti'); // Exact match exists
149
- });
150
-
151
- it('returns exact match for fast + cheap + reasoning + multi', () => {
152
- const key = modelService.negotiateModel(null, {
153
- fast: true,
154
- cheap: true,
155
- reasoning: true,
156
- multi: true,
157
- });
158
- expect(key).toBe('fastCheapReasoningMulti'); // Exact match exists
159
- });
160
- });
161
-
162
- describe('Fallback logic', () => {
163
- beforeEach(() => {
164
- modelService.models = {
165
- fastGoodCheap: new Model({
166
- name: 'fast-good-cheap',
167
- maxContextWindow: 128000,
168
- maxOutputTokens: 16384,
169
- requestTimeout: 1000,
170
- tokenizer,
171
- }),
172
- fastGood: new Model({
173
- name: 'fast-good',
174
- maxContextWindow: 128000,
175
- maxOutputTokens: 16384,
176
- requestTimeout: 1000,
177
- tokenizer,
178
- }),
179
- fastCheap: new Model({
180
- name: 'fast-cheap',
181
- maxContextWindow: 128000,
182
- maxOutputTokens: 8192,
183
- requestTimeout: 1000,
184
- tokenizer,
185
- }),
186
- fastReasoning: new Model({
187
- name: 'fast-reasoning',
188
- maxContextWindow: 200000,
189
- maxOutputTokens: 100000,
190
- requestTimeout: 1000,
191
- tokenizer,
192
- }),
193
- good: new Model({
194
- name: 'good',
195
- maxContextWindow: 128000,
196
- maxOutputTokens: 16384,
197
- requestTimeout: 1000,
198
- tokenizer,
199
- }),
200
- reasoning: new Model({
201
- name: 'reasoning',
202
- maxContextWindow: 200000,
203
- maxOutputTokens: 100000,
204
- requestTimeout: 1000,
205
- tokenizer,
206
- }),
207
- fast: new Model({
208
- name: 'fast',
209
- maxContextWindow: 128000,
210
- maxOutputTokens: 16384,
211
- requestTimeout: 1000,
212
- tokenizer,
213
- }),
214
- cheap: new Model({
215
- name: 'cheap',
216
- maxContextWindow: 128000,
217
- maxOutputTokens: 8192,
218
- requestTimeout: 1000,
219
- tokenizer,
220
- }),
221
- };
222
- });
223
-
224
- it('finds exact match when available', () => {
225
- const key = modelService.negotiateModel(null, { fast: true, good: true });
226
- expect(key).toBe('fastGoodCheap');
227
- });
228
-
229
- it('requires all specified features to match', () => {
230
- // Request multi but no multi models exist - should return undefined
231
- expect(modelService.negotiateModel(null, { fast: true, multi: true })).toBe(undefined);
232
- });
233
-
234
- it('picks higher priority model when multiple match', () => {
235
- // Both fastGoodCheap, fastGood and good match { good: true }, should pick fastGoodCheap (highest priority)
236
- const key = modelService.negotiateModel(null, { good: true });
237
- expect(key).toBe('fastGoodCheap');
238
- });
239
-
240
- it('respects all requirements strictly', () => {
241
- // Request fast + cheap + reasoning - no exact match available, should return undefined since reasoning is requested
242
- expect(modelService.negotiateModel(null, { fast: true, cheap: true, reasoning: true })).toBe(
243
- undefined
244
- );
245
- });
246
-
247
- it('works with single requirements', () => {
248
- const key = modelService.negotiateModel(null, { reasoning: true });
249
- expect(key).toBe('fastReasoning');
250
- });
251
-
252
- it('works with multi requirement when available', () => {
253
- modelService.models.fastGoodMulti = new Model({
254
- name: 'fast-good-multi',
255
- maxContextWindow: 1000000,
256
- maxOutputTokens: 32768,
257
- requestTimeout: 1000,
258
- tokenizer,
259
- });
260
-
261
- const key = modelService.negotiateModel(null, { fast: true, good: true, multi: true });
262
- expect(key).toBe('fastGoodMulti');
263
- });
264
-
265
- it('falls back to best public model when no matches found', () => {
266
- // Request something that doesn't exist with reasoning - should return undefined
267
- expect(
268
- modelService.negotiateModel(null, {
269
- fast: true,
270
- cheap: true,
271
- good: true,
272
- reasoning: true,
273
- multi: true,
274
- })
275
- ).toBe(undefined);
276
- });
277
-
278
- it('prioritizes better combinations over individual features', () => {
279
- // Both fast and fastGoodCheap match { fast: true }, should pick fastGoodCheap
280
- const key = modelService.negotiateModel(null, { fast: true });
281
- expect(key).toBe('fastGoodCheap');
282
- });
283
- });
284
-
285
- describe('Preferred model handling', () => {
286
- beforeEach(() => {
287
- modelService.models = {
288
- fastGood: new Model({
289
- name: 'fast-good',
290
- maxContextWindow: 128000,
291
- maxOutputTokens: 16384,
292
- requestTimeout: 1000,
293
- tokenizer,
294
- }),
295
- customModel: new Model({
296
- name: 'custom',
297
- maxContextWindow: 64000,
298
- maxOutputTokens: 8192,
299
- requestTimeout: 1000,
300
- tokenizer,
301
- }),
302
- };
303
- });
304
-
305
- it('returns preferred model when available and no privacy requested', () => {
306
- const key = modelService.negotiateModel('customModel', { fast: true });
307
- expect(key).toBe('fastGood');
308
- });
309
-
310
- it('ignores preferred model when privacy is requested', () => {
311
- modelService.models.privacy = new Model({
312
- name: 'privacy',
313
- maxContextWindow: 128000,
314
- maxOutputTokens: 8192,
315
- requestTimeout: 1000,
316
- tokenizer,
317
- });
318
-
319
- const key = modelService.negotiateModel('customModel', { privacy: true });
320
- expect(key).toBe('privacy');
321
- });
322
-
323
- it('falls back to negotiation when preferred model does not exist', () => {
324
- const key = modelService.negotiateModel('nonExistentModel', { fast: true });
325
- expect(key).toBe('fastGood');
326
- });
327
- });
328
-
329
- describe('Edge cases', () => {
330
- beforeEach(() => {
331
- modelService.models = {
332
- fastGood: new Model({
333
- name: 'fast-good',
334
- maxContextWindow: 128000,
335
- maxOutputTokens: 16384,
336
- requestTimeout: 1000,
337
- tokenizer,
338
- }),
339
- };
340
- });
341
-
342
- it('handles empty negotiation object', () => {
343
- const key = modelService.negotiateModel(null, {});
344
- expect(key).toBe('fastGood');
345
- });
346
-
347
- it('handles undefined negotiation', () => {
348
- const key = modelService.negotiateModel(null);
349
- expect(key).toBe('fastGood');
350
- });
351
-
352
- it('handles single flag requests', () => {
353
- const key = modelService.negotiateModel(null, { fast: true });
354
- expect(key).toBe('fastGood');
355
- });
356
-
357
- it('prioritizes reasoning over good when both are requested', () => {
358
- modelService.models.fastReasoning = new Model({
359
- name: 'fast-reasoning',
360
- maxContextWindow: 200000,
361
- maxOutputTokens: 100000,
362
- requestTimeout: 1000,
363
- tokenizer,
364
- });
365
-
366
- // Request fast + reasoning + good but no model has all three - should return undefined
367
- expect(modelService.negotiateModel(null, { fast: true, reasoning: true, good: true })).toBe(
368
- undefined
369
- );
370
- });
371
- });
372
-
373
- describe('Property negation', () => {
374
- beforeEach(() => {
375
- modelService.models = {
376
- fastGoodCheap: new Model({
377
- name: 'fast-good-cheap',
378
- maxContextWindow: 128000,
379
- maxOutputTokens: 16384,
380
- requestTimeout: 1000,
381
- tokenizer,
382
- }),
383
- fastGood: new Model({
384
- name: 'fast-good',
385
- maxContextWindow: 128000,
386
- maxOutputTokens: 16384,
387
- requestTimeout: 1000,
388
- tokenizer,
389
- }),
390
- good: new Model({
391
- name: 'good',
392
- maxContextWindow: 128000,
393
- maxOutputTokens: 16384,
394
- requestTimeout: 1000,
395
- tokenizer,
396
- }),
397
- fast: new Model({
398
- name: 'fast',
399
- maxContextWindow: 128000,
400
- maxOutputTokens: 16384,
401
- requestTimeout: 1000,
402
- tokenizer,
403
- }),
404
- reasoning: new Model({
405
- name: 'reasoning',
406
- maxContextWindow: 200000,
407
- maxOutputTokens: 100000,
408
- requestTimeout: 1000,
409
- tokenizer,
410
- }),
411
- };
412
- });
413
-
414
- it('excludes models with negated properties', () => {
415
- // Request good but NOT fast - should pick 'good' over 'fastGood'
416
- const key = modelService.negotiateModel(null, { good: true, fast: false });
417
- expect(key).toBe('good');
418
- });
419
-
420
- it('excludes models with multiple negated properties', () => {
421
- // Request good but NOT fast and NOT cheap - should pick 'good'
422
- const key = modelService.negotiateModel(null, { good: true, fast: false, cheap: false });
423
- expect(key).toBe('good');
424
- });
425
-
426
- it('works with only negated properties', () => {
427
- // Request NOT fast - should pick 'good' (first non-fast model in priority)
428
- const key = modelService.negotiateModel(null, { fast: false });
429
- expect(key).toBe('good');
430
- });
431
-
432
- it('combines positive and negative requirements', () => {
433
- // Request fast but NOT good - should pick 'fast' over 'fastGood'
434
- // fastGoodCheap has both fast and good, so it's excluded by good: false
435
- // fastGood has both fast and good, so it's excluded by good: false
436
- // fast has fast but no good, so it matches
437
- const key = modelService.negotiateModel(null, { fast: true, good: false });
438
- expect(key).toBe('fast');
439
- });
440
-
441
- it('falls back when negation eliminates all matches', () => {
442
- // Request NOT reasoning (all models are non-reasoning, so should pick first priority)
443
- const key = modelService.negotiateModel(null, { good: false });
444
- expect(key).toBe('fast');
445
- });
446
- });
447
- });
@@ -1,147 +0,0 @@
1
- import { createClient } from 'redis';
2
-
3
- let client;
4
- let constructingClient;
5
-
6
- class NullRedisClient {
7
- constructor() {
8
- this.store = {};
9
- }
10
-
11
- get(key) {
12
- // Redis returns null, not undefined
13
- return this.store[key] ?? null;
14
- }
15
-
16
- del(key) {
17
- delete this.store[key];
18
- }
19
-
20
- set(key, value, _options) {
21
- this.store[key] = value;
22
- }
23
-
24
- disconnect() {
25
- // no implementation
26
- }
27
- }
28
-
29
- class SafeRedisClient {
30
- constructor(redisClient) {
31
- this.redisClient = redisClient;
32
- this.fallbackClient = new NullRedisClient();
33
- }
34
-
35
- async get(key) {
36
- try {
37
- return await this.redisClient.get(key);
38
- } catch (error) {
39
- if (this.isConnectionError(error)) {
40
- console.warn('Redis connection lost, falling back to in-memory cache');
41
- return this.fallbackClient.get(key);
42
- }
43
- throw error;
44
- }
45
- }
46
-
47
- async set(key, value, options) {
48
- try {
49
- return await this.redisClient.set(key, value, options);
50
- } catch (error) {
51
- if (this.isConnectionError(error)) {
52
- console.warn('Redis connection lost, falling back to in-memory cache');
53
- return this.fallbackClient.set(key, value, options);
54
- }
55
- throw error;
56
- }
57
- }
58
-
59
- async del(key) {
60
- try {
61
- return await this.redisClient.del(key);
62
- } catch (error) {
63
- if (this.isConnectionError(error)) {
64
- console.warn('Redis connection lost, falling back to in-memory cache');
65
- return this.fallbackClient.del(key);
66
- }
67
- throw error;
68
- }
69
- }
70
-
71
- async disconnect() {
72
- try {
73
- return await this.redisClient.disconnect();
74
- } catch {
75
- // Ignore disconnect errors
76
- }
77
- }
78
-
79
- isConnectionError(error) {
80
- return (
81
- error.message.includes('client is closed') ||
82
- error.message.includes('ECONNREFUSED') ||
83
- error.message.includes('connection') ||
84
- error.code === 'ECONNREFUSED'
85
- );
86
- }
87
- }
88
-
89
- const constructClient = async () => {
90
- if (process.env.TEST === 'true' && process.env.EXAMPLES !== 'true') {
91
- client = new NullRedisClient();
92
- return;
93
- }
94
-
95
- const redisClient = createClient({
96
- host: process.env.REDIS_HOST ?? 'localhost',
97
- port: process.env.REDIS_PORT ?? 6379,
98
- });
99
-
100
- redisClient.on('error', (error) => {
101
- if (client instanceof NullRedisClient) {
102
- return;
103
- }
104
-
105
- if (/ECONNREFUSED/.test(error.message)) {
106
- console.error(
107
- `Redis service [warning]: "${error.message}" Falling back to mock Redis client. This may incur greater usage costs and have slower response times.`
108
- );
109
- client = new NullRedisClient();
110
- } else {
111
- console.error(`Redis service [error]: ${error.message}`);
112
- client = new NullRedisClient();
113
- }
114
-
115
- // Safely disconnect the Redis client
116
- redisClient.disconnect().catch(() => {
117
- // Ignore disconnect errors
118
- });
119
- });
120
-
121
- try {
122
- await redisClient.connect();
123
- client = new SafeRedisClient(redisClient);
124
- } catch (error) {
125
- console.error(
126
- `Redis service create [warning]: "${error.message}" Falling back to mock Redis client. This may incur greater usage costs and have slower response times.`
127
- );
128
- client = new NullRedisClient();
129
- }
130
- };
131
-
132
- export const getClient = async () => {
133
- if (client) {
134
- return client;
135
- }
136
-
137
- if (!constructingClient) {
138
- constructingClient = constructClient();
139
- }
140
-
141
- await constructingClient;
142
- return client;
143
- };
144
-
145
- export const setClient = (newClient) => {
146
- client = newClient;
147
- };
package/src/test/setup.js DELETED
@@ -1,20 +0,0 @@
1
- import { afterAll, beforeEach } from 'vitest';
2
- import dotenv from 'dotenv';
3
- import { getClient as getRedis } from '../services/redis/index.js';
4
-
5
- // Load environment variables from .env file
6
- dotenv.config();
7
-
8
- let redisClient;
9
-
10
- beforeEach(async () => {
11
- // Get a fresh Redis client for each test
12
- redisClient = await getRedis();
13
- });
14
-
15
- afterAll(async () => {
16
- // Clean up Redis client after all tests
17
- if (redisClient) {
18
- await redisClient.disconnect();
19
- }
20
- });
@@ -1,26 +0,0 @@
1
- # Verblets
2
-
3
- The `verblets` directory contains individual utilities that wrap specific language-model workflows. Each verblet exports a single function and usually includes its own examples, tests and optional JSON schema.
4
-
5
- Available verblets:
6
-
7
- - [auto](./auto)
8
- - [bool](./bool)
9
- - [name](./name) - generate evocative names from text
10
- - [enum](./enum)
11
- - [intent](./intent)
12
- - [number](./number)
13
- - [number-with-units](./number-with-units)
14
- - [date](../chains/date)
15
- - [sentiment](./sentiment) - classify text sentiment
16
- - [schema-org](./schema-org)
17
- - [name-similar-to](./name-similar-to) - suggest short names matching a style
18
- - [name](./name) - name something from a definition or description
19
- - [to-object](./to-object) – see its [README](./to-object/README.md) for details.
20
- - [list-map](./list-map) - map lists with prompts
21
- - [list-reduce](./list-reduce) - reduce lists prompts
22
- - [list-filter](./list-filter) - filter lists with custom instructions
23
- - [list-group](./list-group) - group lists into categories with prompts
24
- - [list-expand](./list-expand) - expand lists with similar items with prompts
25
-
26
- Use these modules directly or compose them inside [chains](../chains/README.md).
@@ -1,31 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
-
3
- import auto from './index.js';
4
-
5
- const examples = [
6
- {
7
- inputs: { text: 'test' },
8
- want: {
9
- typeOfResult: 'object',
10
- hasProperties: ['functionArgsAsArray'],
11
- },
12
- },
13
- ];
14
-
15
- describe('Auto verblet', () => {
16
- examples.forEach((example) => {
17
- it(example.inputs.text, async () => {
18
- const result = await auto(example.inputs.text);
19
-
20
- if (example.want.typeOfResult) {
21
- expect(typeof result).toStrictEqual(example.want.typeOfResult);
22
- }
23
-
24
- if (example.want.hasProperties) {
25
- example.want.hasProperties.forEach((prop) => {
26
- expect(result).toHaveProperty(prop);
27
- });
28
- }
29
- });
30
- });
31
- });
@@ -1,28 +0,0 @@
1
- import chatGPT from '../../lib/chatgpt/index.js';
2
- import schemas from '../../json-schemas/index.js';
3
-
4
- export default async (text, config = {}) => {
5
- const { llm, ...options } = config;
6
- const tools = schemas.map((schema) => ({
7
- type: 'function',
8
- function: schema,
9
- }));
10
-
11
- const functionFound = await chatGPT(text, {
12
- modelOptions: {
13
- // toolChoice: 'auto' // by default
14
- tools,
15
- ...llm,
16
- },
17
- ...options,
18
- });
19
-
20
- const functionArgs = functionFound.arguments;
21
-
22
- const functionArgsAsArray = Array.isArray(functionArgs) ? functionArgs : [functionArgs];
23
-
24
- return {
25
- ...functionFound,
26
- functionArgsAsArray,
27
- };
28
- };