@far-world-labs/verblets 0.2.0 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (330) hide show
  1. package/README.md +86 -213
  2. package/dist/index.browser.js +74 -0
  3. package/dist/index.js +548 -0
  4. package/dist/shared-C6kPWghF.js +7806 -0
  5. package/package.json +32 -11
  6. package/.cursor/launch.json +0 -30
  7. package/.cursor/settings.json +0 -20
  8. package/.github/workflows/branch-protection.yml +0 -22
  9. package/.github/workflows/ci.yml +0 -165
  10. package/.husky/pre-commit +0 -4
  11. package/.prettierrc +0 -6
  12. package/.release-it.json +0 -12
  13. package/.vitest.config.examples.js +0 -12
  14. package/.vitest.config.js +0 -8
  15. package/.vscode/launch.json +0 -31
  16. package/AGENTS.md +0 -220
  17. package/DEVELOPING.md +0 -105
  18. package/docker-compose.yml +0 -7
  19. package/eslint.config.js +0 -80
  20. package/scripts/clear-redis.js +0 -74
  21. package/scripts/generate-chain/index.js +0 -111
  22. package/scripts/generate-lib/index.js +0 -68
  23. package/scripts/generate-test/index.js +0 -137
  24. package/scripts/generate-verblet/README.md +0 -17
  25. package/scripts/generate-verblet/index.js +0 -110
  26. package/scripts/run.sh +0 -15
  27. package/scripts/runner/index.js +0 -56
  28. package/scripts/simple-editor/README.md +0 -34
  29. package/scripts/simple-editor/index.js +0 -79
  30. package/scripts/summarize-files/index.js +0 -70
  31. package/src/chains/README.md +0 -30
  32. package/src/chains/anonymize/README.md +0 -21
  33. package/src/chains/anonymize/index.examples.js +0 -75
  34. package/src/chains/anonymize/index.js +0 -121
  35. package/src/chains/anonymize/index.spec.js +0 -78
  36. package/src/chains/bulk-central-tendency/index.examples.js +0 -138
  37. package/src/chains/bulk-central-tendency/index.js +0 -91
  38. package/src/chains/bulk-filter/README.md +0 -21
  39. package/src/chains/bulk-filter/index.examples.js +0 -22
  40. package/src/chains/bulk-filter/index.js +0 -58
  41. package/src/chains/bulk-filter/index.spec.js +0 -38
  42. package/src/chains/bulk-find/README.md +0 -16
  43. package/src/chains/bulk-find/index.examples.js +0 -20
  44. package/src/chains/bulk-find/index.js +0 -30
  45. package/src/chains/bulk-find/index.spec.js +0 -26
  46. package/src/chains/bulk-group/README.md +0 -23
  47. package/src/chains/bulk-group/index.examples.js +0 -18
  48. package/src/chains/bulk-group/index.js +0 -34
  49. package/src/chains/bulk-group/index.spec.js +0 -41
  50. package/src/chains/bulk-map/README.md +0 -43
  51. package/src/chains/bulk-map/index.examples.js +0 -17
  52. package/src/chains/bulk-map/index.js +0 -86
  53. package/src/chains/bulk-map/index.spec.js +0 -44
  54. package/src/chains/bulk-reduce/README.md +0 -12
  55. package/src/chains/bulk-reduce/index.examples.js +0 -15
  56. package/src/chains/bulk-reduce/index.js +0 -13
  57. package/src/chains/bulk-reduce/index.spec.js +0 -25
  58. package/src/chains/bulk-score/README.md +0 -16
  59. package/src/chains/bulk-score/bulk-score-result.json +0 -18
  60. package/src/chains/bulk-score/index.examples.js +0 -22
  61. package/src/chains/bulk-score/index.js +0 -133
  62. package/src/chains/bulk-score/index.spec.js +0 -30
  63. package/src/chains/category-samples/README.md +0 -61
  64. package/src/chains/category-samples/index.examples.js +0 -103
  65. package/src/chains/category-samples/index.js +0 -134
  66. package/src/chains/collect-terms/README.md +0 -12
  67. package/src/chains/collect-terms/index.examples.js +0 -16
  68. package/src/chains/collect-terms/index.js +0 -44
  69. package/src/chains/collect-terms/index.spec.js +0 -25
  70. package/src/chains/conversation/README.md +0 -26
  71. package/src/chains/conversation/index.examples.js +0 -398
  72. package/src/chains/conversation/index.js +0 -126
  73. package/src/chains/conversation/index.spec.js +0 -148
  74. package/src/chains/conversation/turn-policies.js +0 -93
  75. package/src/chains/conversation/turn-policies.md +0 -123
  76. package/src/chains/conversation/turn-policies.spec.js +0 -135
  77. package/src/chains/date/README.md +0 -12
  78. package/src/chains/date/index.examples.js +0 -47
  79. package/src/chains/date/index.js +0 -74
  80. package/src/chains/date/index.spec.js +0 -62
  81. package/src/chains/disambiguate/README.md +0 -22
  82. package/src/chains/disambiguate/disambiguate-meanings-result.json +0 -16
  83. package/src/chains/disambiguate/index.examples.js +0 -18
  84. package/src/chains/disambiguate/index.js +0 -92
  85. package/src/chains/disambiguate/index.spec.js +0 -25
  86. package/src/chains/dismantle/README.md +0 -67
  87. package/src/chains/dismantle/dismantle.examples.js +0 -27
  88. package/src/chains/dismantle/index.examples.js +0 -30
  89. package/src/chains/dismantle/index.js +0 -303
  90. package/src/chains/dismantle/index.spec.js +0 -32
  91. package/src/chains/expect/README.md +0 -171
  92. package/src/chains/expect/index.examples.js +0 -146
  93. package/src/chains/expect/index.js +0 -207
  94. package/src/chains/expect/index.spec.js +0 -324
  95. package/src/chains/filter-ambiguous/README.md +0 -11
  96. package/src/chains/filter-ambiguous/index.examples.js +0 -20
  97. package/src/chains/filter-ambiguous/index.js +0 -49
  98. package/src/chains/filter-ambiguous/index.spec.js +0 -31
  99. package/src/chains/glossary/README.md +0 -19
  100. package/src/chains/glossary/index.examples.js +0 -386
  101. package/src/chains/glossary/index.js +0 -75
  102. package/src/chains/glossary/index.spec.js +0 -19
  103. package/src/chains/intersections/README.md +0 -166
  104. package/src/chains/intersections/index.examples.js +0 -280
  105. package/src/chains/intersections/index.js +0 -218
  106. package/src/chains/intersections/intersection-result.json +0 -38
  107. package/src/chains/list/index.examples.js +0 -68
  108. package/src/chains/list/index.js +0 -214
  109. package/src/chains/list/index.spec.js +0 -67
  110. package/src/chains/list/list-result.json +0 -16
  111. package/src/chains/list/schema.json +0 -24
  112. package/src/chains/llm-logger/README.md +0 -366
  113. package/src/chains/llm-logger/index.js +0 -591
  114. package/src/chains/llm-logger/index.spec.js +0 -391
  115. package/src/chains/llm-logger/schema.json +0 -105
  116. package/src/chains/questions/index.examples.js +0 -69
  117. package/src/chains/questions/index.js +0 -135
  118. package/src/chains/questions/index.spec.js +0 -29
  119. package/src/chains/scan-js/index.js +0 -116
  120. package/src/chains/set-interval/README.md +0 -81
  121. package/src/chains/set-interval/index.examples.js +0 -64
  122. package/src/chains/set-interval/index.js +0 -152
  123. package/src/chains/set-interval/index.spec.js +0 -70
  124. package/src/chains/socratic/README.md +0 -17
  125. package/src/chains/socratic/index.js +0 -64
  126. package/src/chains/socratic/index.spec.js +0 -24
  127. package/src/chains/sort/index.examples.js +0 -36
  128. package/src/chains/sort/index.js +0 -163
  129. package/src/chains/sort/index.spec.js +0 -112
  130. package/src/chains/sort/sort-result.json +0 -16
  131. package/src/chains/summary-map/README.md +0 -41
  132. package/src/chains/summary-map/index.examples.js +0 -64
  133. package/src/chains/summary-map/index.js +0 -226
  134. package/src/chains/summary-map/index.spec.js +0 -153
  135. package/src/chains/test/index.js +0 -114
  136. package/src/chains/test-advice/index.js +0 -35
  137. package/src/chains/themes/README.md +0 -20
  138. package/src/chains/themes/index.examples.js +0 -17
  139. package/src/chains/themes/index.js +0 -28
  140. package/src/chains/themes/index.spec.js +0 -19
  141. package/src/chains/veiled-variants/index.examples.js +0 -18
  142. package/src/chains/veiled-variants/index.js +0 -107
  143. package/src/chains/veiled-variants/index.spec.js +0 -40
  144. package/src/constants/common.js +0 -13
  145. package/src/constants/messages.js +0 -3
  146. package/src/constants/models.js +0 -184
  147. package/src/index.js +0 -203
  148. package/src/json-schemas/README.md +0 -13
  149. package/src/json-schemas/cars-test.json +0 -11
  150. package/src/json-schemas/index.js +0 -12
  151. package/src/json-schemas/intent.json +0 -38
  152. package/src/json-schemas/schema-dot-org-photograph.json +0 -133
  153. package/src/json-schemas/schema-dot-org-place.json +0 -129
  154. package/src/lib/README.md +0 -26
  155. package/src/lib/any-signal/index.js +0 -28
  156. package/src/lib/assert/README.md +0 -84
  157. package/src/lib/assert/index.js +0 -50
  158. package/src/lib/bulk-filter/README.md +0 -22
  159. package/src/lib/bulk-filter/index.examples.js +0 -27
  160. package/src/lib/bulk-filter/index.js +0 -63
  161. package/src/lib/bulk-filter/index.spec.js +0 -38
  162. package/src/lib/bulk-find/README.md +0 -18
  163. package/src/lib/bulk-find/index.examples.js +0 -19
  164. package/src/lib/bulk-find/index.js +0 -30
  165. package/src/lib/bulk-find/index.spec.js +0 -41
  166. package/src/lib/chatgpt/index.js +0 -163
  167. package/src/lib/combinations/index.js +0 -30
  168. package/src/lib/combinations/index.spec.js +0 -23
  169. package/src/lib/editor/index.js +0 -31
  170. package/src/lib/functional/index.js +0 -28
  171. package/src/lib/logger-service/index.js +0 -32
  172. package/src/lib/parse-js-parts/index.js +0 -321
  173. package/src/lib/parse-js-parts/index.spec.js +0 -156
  174. package/src/lib/parse-llm-list/README.md +0 -39
  175. package/src/lib/parse-llm-list/index.js +0 -54
  176. package/src/lib/parse-llm-list/index.spec.js +0 -59
  177. package/src/lib/path-aliases/index.js +0 -37
  178. package/src/lib/path-aliases/index.spec.js +0 -64
  179. package/src/lib/pave/index.js +0 -34
  180. package/src/lib/pave/index.spec.js +0 -76
  181. package/src/lib/prompt-cache/index.js +0 -50
  182. package/src/lib/retry/index.js +0 -66
  183. package/src/lib/retry/index.spec.js +0 -86
  184. package/src/lib/ring-buffer/README.md +0 -82
  185. package/src/lib/ring-buffer/index.js +0 -235
  186. package/src/lib/ring-buffer/index.spec.js +0 -388
  187. package/src/lib/search-best-first/city-walk.spec.js +0 -37
  188. package/src/lib/search-best-first/index.js +0 -97
  189. package/src/lib/search-best-first/index.spec.js +0 -35
  190. package/src/lib/search-js-files/code-features-property-definitions.json +0 -123
  191. package/src/lib/search-js-files/index.examples.js +0 -22
  192. package/src/lib/search-js-files/index.js +0 -155
  193. package/src/lib/search-js-files/index.spec.js +0 -34
  194. package/src/lib/search-js-files/scan-file.js +0 -242
  195. package/src/lib/shorten-text/index.js +0 -25
  196. package/src/lib/shorten-text/index.spec.js +0 -68
  197. package/src/lib/strip-numeric/index.js +0 -5
  198. package/src/lib/strip-response/index.js +0 -30
  199. package/src/lib/template-replace/index.js +0 -23
  200. package/src/lib/template-replace/index.spec.js +0 -60
  201. package/src/lib/timed-abort-controller/index.js +0 -41
  202. package/src/lib/to-bool/index.js +0 -8
  203. package/src/lib/to-date/index.js +0 -11
  204. package/src/lib/to-enum/index.js +0 -14
  205. package/src/lib/to-number/index.js +0 -12
  206. package/src/lib/to-number-with-units/index.js +0 -51
  207. package/src/lib/transcribe/index.js +0 -78
  208. package/src/prompts/README.md +0 -17
  209. package/src/prompts/as-enum.js +0 -5
  210. package/src/prompts/as-json-schema.js +0 -9
  211. package/src/prompts/as-object-with-schema.js +0 -26
  212. package/src/prompts/as-schema-org-text.js +0 -25
  213. package/src/prompts/as-schema-org-type.js +0 -1
  214. package/src/prompts/blog-post.js +0 -7
  215. package/src/prompts/code-features.js +0 -24
  216. package/src/prompts/constants.js +0 -101
  217. package/src/prompts/features-json-schema.js +0 -27
  218. package/src/prompts/generate-collection.js +0 -26
  219. package/src/prompts/generate-list.js +0 -48
  220. package/src/prompts/generate-questions.js +0 -19
  221. package/src/prompts/index.js +0 -20
  222. package/src/prompts/intent.js +0 -60
  223. package/src/prompts/output-succinct-names.js +0 -3
  224. package/src/prompts/select-from-threshold.js +0 -17
  225. package/src/prompts/sort.js +0 -31
  226. package/src/prompts/style.js +0 -38
  227. package/src/prompts/summarize.js +0 -13
  228. package/src/prompts/token-budget.js +0 -3
  229. package/src/prompts/wrap-list.js +0 -11
  230. package/src/prompts/wrap-variable.js +0 -36
  231. package/src/services/llm-model/global-overrides.spec.js +0 -432
  232. package/src/services/llm-model/index.js +0 -308
  233. package/src/services/llm-model/model.js +0 -21
  234. package/src/services/llm-model/negotiate.spec.js +0 -447
  235. package/src/services/redis/index.js +0 -147
  236. package/src/test/setup.js +0 -20
  237. package/src/verblets/README.md +0 -26
  238. package/src/verblets/auto/index.examples.js +0 -31
  239. package/src/verblets/auto/index.js +0 -28
  240. package/src/verblets/auto/index.spec.js +0 -32
  241. package/src/verblets/bool/README.md +0 -36
  242. package/src/verblets/bool/index.examples.js +0 -80
  243. package/src/verblets/bool/index.js +0 -25
  244. package/src/verblets/bool/index.schema.json +0 -14
  245. package/src/verblets/bool/index.spec.js +0 -33
  246. package/src/verblets/central-tendency/README.md +0 -166
  247. package/src/verblets/central-tendency/central-tendency-result.json +0 -24
  248. package/src/verblets/central-tendency/index.examples.js +0 -196
  249. package/src/verblets/central-tendency/index.js +0 -171
  250. package/src/verblets/central-tendency/index.spec.js +0 -148
  251. package/src/verblets/conversation-turn/README.md +0 -33
  252. package/src/verblets/conversation-turn/index.examples.js +0 -218
  253. package/src/verblets/conversation-turn/index.js +0 -68
  254. package/src/verblets/conversation-turn/index.spec.js +0 -77
  255. package/src/verblets/conversation-turn-multi/README.md +0 -31
  256. package/src/verblets/conversation-turn-multi/index.examples.js +0 -160
  257. package/src/verblets/conversation-turn-multi/index.js +0 -104
  258. package/src/verblets/conversation-turn-multi/index.spec.js +0 -63
  259. package/src/verblets/enum/index.examples.js +0 -30
  260. package/src/verblets/enum/index.js +0 -18
  261. package/src/verblets/enum/index.spec.js +0 -35
  262. package/src/verblets/expect/README.md +0 -64
  263. package/src/verblets/expect/index.examples.js +0 -109
  264. package/src/verblets/expect/index.js +0 -75
  265. package/src/verblets/expect/index.spec.js +0 -127
  266. package/src/verblets/intent/index.examples.js +0 -139
  267. package/src/verblets/intent/index.js +0 -60
  268. package/src/verblets/intent/index.spec.js +0 -31
  269. package/src/verblets/intersection/README.md +0 -16
  270. package/src/verblets/intersection/index.examples.js +0 -89
  271. package/src/verblets/intersection/index.js +0 -125
  272. package/src/verblets/intersection/index.spec.js +0 -60
  273. package/src/verblets/intersection/intersection-result.json +0 -16
  274. package/src/verblets/list-expand/README.md +0 -10
  275. package/src/verblets/list-expand/index.examples.js +0 -14
  276. package/src/verblets/list-expand/index.js +0 -104
  277. package/src/verblets/list-expand/index.spec.js +0 -18
  278. package/src/verblets/list-expand/list-expand-result.json +0 -16
  279. package/src/verblets/list-filter/README.md +0 -22
  280. package/src/verblets/list-filter/index.examples.js +0 -26
  281. package/src/verblets/list-filter/index.js +0 -18
  282. package/src/verblets/list-filter/index.spec.js +0 -19
  283. package/src/verblets/list-find/README.md +0 -11
  284. package/src/verblets/list-find/index.examples.js +0 -15
  285. package/src/verblets/list-find/index.js +0 -17
  286. package/src/verblets/list-find/index.spec.js +0 -19
  287. package/src/verblets/list-group/README.md +0 -16
  288. package/src/verblets/list-group/index.examples.js +0 -16
  289. package/src/verblets/list-group/index.js +0 -112
  290. package/src/verblets/list-group/index.spec.js +0 -35
  291. package/src/verblets/list-group/list-group-result.json +0 -16
  292. package/src/verblets/list-map/README.md +0 -11
  293. package/src/verblets/list-map/index.examples.js +0 -15
  294. package/src/verblets/list-map/index.js +0 -26
  295. package/src/verblets/list-map/index.spec.js +0 -17
  296. package/src/verblets/list-reduce/README.md +0 -10
  297. package/src/verblets/list-reduce/index.examples.js +0 -14
  298. package/src/verblets/list-reduce/index.js +0 -21
  299. package/src/verblets/list-reduce/index.spec.js +0 -27
  300. package/src/verblets/list-reduce/index.spec.jsx +0 -27
  301. package/src/verblets/name/README.md +0 -15
  302. package/src/verblets/name/index.examples.js +0 -28
  303. package/src/verblets/name/index.js +0 -19
  304. package/src/verblets/name/index.spec.js +0 -33
  305. package/src/verblets/name-similar-to/README.md +0 -26
  306. package/src/verblets/name-similar-to/index.examples.js +0 -18
  307. package/src/verblets/name-similar-to/index.js +0 -20
  308. package/src/verblets/name-similar-to/index.spec.js +0 -13
  309. package/src/verblets/number/index.examples.js +0 -199
  310. package/src/verblets/number/index.js +0 -25
  311. package/src/verblets/number/index.spec.js +0 -33
  312. package/src/verblets/number-with-units/index.examples.js +0 -38
  313. package/src/verblets/number-with-units/index.js +0 -84
  314. package/src/verblets/number-with-units/index.spec.js +0 -46
  315. package/src/verblets/number-with-units/number-with-units-result.json +0 -23
  316. package/src/verblets/people-list/README.md +0 -28
  317. package/src/verblets/people-list/index.examples.js +0 -184
  318. package/src/verblets/people-list/index.js +0 -44
  319. package/src/verblets/people-list/index.spec.js +0 -49
  320. package/src/verblets/schema-org/index.examples.js +0 -51
  321. package/src/verblets/schema-org/index.js +0 -37
  322. package/src/verblets/schema-org/index.spec.js +0 -39
  323. package/src/verblets/sentiment/README.md +0 -10
  324. package/src/verblets/sentiment/index.examples.js +0 -20
  325. package/src/verblets/sentiment/index.js +0 -9
  326. package/src/verblets/sentiment/index.spec.js +0 -20
  327. package/src/verblets/to-object/README.md +0 -38
  328. package/src/verblets/to-object/index.examples.js +0 -29
  329. package/src/verblets/to-object/index.js +0 -131
  330. package/src/verblets/to-object/index.spec.js +0 -71
@@ -1,17 +0,0 @@
1
- import * as R from 'ramda';
2
-
3
- // Returns a modifier function that generates a prompt fragment based on a given value
4
- /*
5
- * let openEndedDegree = findDegreeModifier(openEnded, [
6
- * { threshold: 0.2, degree: 'must not be' },
7
- * { threshold: 0.4, degree: 'must be minimally' },
8
- * { threshold: 0.6, degree: 'must be somewhat' },
9
- * { threshold: 0.8, degree: 'must be very' },
10
- * { threshold: 1.0, degree: 'must be extremely' },
11
- * ]);
12
- * const openEndedPrompt = `Questions ${openEndedDegree} open-ended. `
13
- */
14
- export default (value, thresholds = []) => {
15
- const threshold = thresholds.find((t) => value <= t.threshold) || R.last(thresholds);
16
- return threshold.degree;
17
- };
@@ -1,31 +0,0 @@
1
- import wrapVariable from './wrap-variable.js';
2
- import {
3
- contentIsDetails,
4
- contentIsFixes,
5
- contentIsMain,
6
- contentIsSortCriteria,
7
- onlyJSONStringArray,
8
- } from './constants.js';
9
-
10
- export const defaultSortDescription = 'alphabetical order';
11
- export const defaultFixes = 'Ignore duplicates in the list';
12
- export const defaultSortOrder = 'descending';
13
-
14
- export default (
15
- { description = defaultSortDescription, fixes = defaultFixes, sortOrder = defaultSortOrder },
16
- list
17
- ) => {
18
- const listLines = JSON.stringify(list, undefined, 2);
19
-
20
- return `${contentIsSortCriteria} ${wrapVariable(description, {
21
- tag: 'criteria',
22
- })}
23
-
24
- ${contentIsMain} ${wrapVariable(listLines, { tag: 'main-content' })}
25
-
26
- ${contentIsDetails} ${sortOrder} order
27
-
28
- ${contentIsFixes} ${wrapVariable(fixes, { tag: 'fixes' })}
29
-
30
- ${onlyJSONStringArray}`;
31
- };
@@ -1,38 +0,0 @@
1
- export default (
2
- text,
3
- {
4
- tone = ['informal'],
5
- vocabulary = ['software engineering'],
6
- sentenceStructure = ['varied sentence length', 'active voice'],
7
- pointOfView = ['first person plural'],
8
- noise = 0,
9
- minWords = 0,
10
- maxWords,
11
- } = {}
12
- ) => {
13
- const toneModifiers = `Tone: ${tone.join(', ')}`;
14
- const vocabularyModifiers = `Vocabulary: ${vocabulary.join(', ')}`;
15
- const sentenceStructureModifiers = `Sentence structure: ${sentenceStructure.join(', ')}`;
16
- const pointOfViewModifiers = `Point of view: ${pointOfView.join(', ')}`;
17
- const lengthModifier = `Use between ${minWords} and ${maxWords ?? 'any number'} of words`;
18
-
19
- let noiseModifier = '';
20
- if (noise > 0.5) {
21
- noiseModifier =
22
- "Completely reshape the ideas here, don't stick with the original structure. Don't change the meaning of the content though.";
23
- }
24
-
25
- return `Rewrite the following content:
26
- \`\`\`
27
- ${text}
28
- \`\`\`
29
-
30
- Use the following style:
31
- ${toneModifiers}
32
- ${vocabularyModifiers}
33
- ${sentenceStructureModifiers}
34
- ${pointOfViewModifiers}
35
- ${lengthModifier}
36
- ${noiseModifier}
37
- `;
38
- };
@@ -1,13 +0,0 @@
1
- import wrapVariable from './wrap-variable.js';
2
- import { onlyFullCode } from './constants.js';
3
-
4
- export default (text, instructions = '') => {
5
- return `Summarize the following content. ${onlyFullCode}
6
-
7
- ${wrapVariable(instructions, {
8
- forceHTML: true,
9
- tag: 'summarization-instructions',
10
- })}
11
-
12
- ${wrapVariable(text, { forceHTML: true, tag: 'content-to-summarize' })}`;
13
- };
@@ -1,3 +0,0 @@
1
- export default (budget = 10) => {
2
- return `Keep the output within ${budget} tokens.`;
3
- };
@@ -1,11 +0,0 @@
1
- import wrapVariable from './wrap-variable.js';
2
-
3
- export default (list = [], { introText = 'Consider the following items:' } = {}) => {
4
- const listText = list.map((f, i) => ` - ${i + 1}. ${f}`).join('\n');
5
-
6
- let listFragment = wrapVariable('\n');
7
- if (list.length) {
8
- listFragment = `${introText} ${wrapVariable(listText)}`;
9
- }
10
- return listFragment;
11
- };
@@ -1,36 +0,0 @@
1
- export default (
2
- variable,
3
- { forceHTML = false, name, tag = 'data', title, fit = 'comfortable' } = {}
4
- ) => {
5
- if (!variable) {
6
- return '';
7
- }
8
-
9
- let nameAttribute = '';
10
- if (name) {
11
- nameAttribute = `name="${name}"`;
12
- }
13
-
14
- let variableResolved = typeof variable !== 'undefined' ? variable : '';
15
- if (typeof variable !== 'string') {
16
- variableResolved = JSON.stringify(variable, null, 2);
17
- }
18
-
19
- const isHTML = /\n/.test(variableResolved) || forceHTML || name;
20
- let variableWrapped = !isHTML ? `"${variableResolved}"` : variableResolved;
21
- if (isHTML) {
22
- let fitChar = '\n';
23
- if (fit !== 'comfortable') {
24
- fitChar = '';
25
- }
26
-
27
- variableWrapped = `<${tag}${nameAttribute}>${fitChar}${variableResolved}${fitChar}</${tag}>`;
28
- }
29
-
30
- let titlePrefixed = variableWrapped;
31
- if (title && variableResolved.length > 0) {
32
- titlePrefixed = `${title} ${variableWrapped}`;
33
- }
34
-
35
- return titlePrefixed;
36
- };
@@ -1,432 +0,0 @@
1
- import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
2
- import fetch from 'node-fetch';
3
- import modelService from './index.js';
4
- import Model from './model.js';
5
-
6
- import { run as chatgptRun } from '../../lib/chatgpt/index.js';
7
-
8
- // Mock node-fetch before importing chatgpt
9
- vi.mock('node-fetch', () => ({
10
- default: vi.fn(),
11
- }));
12
-
13
- // Mock Redis
14
- vi.mock('../../services/redis/index.js', () => ({
15
- getClient: vi.fn().mockResolvedValue({
16
- get: vi.fn().mockResolvedValue(null),
17
- setex: vi.fn().mockResolvedValue('OK'),
18
- }),
19
- }));
20
-
21
- // Mock the prompt cache to avoid Redis dependencies
22
- vi.mock('../../lib/prompt-cache/index.js', () => ({
23
- get: vi.fn().mockResolvedValue({ result: null }),
24
- set: vi.fn().mockResolvedValue('OK'),
25
- }));
26
-
27
- // Helper tokenizer
28
- const tokenizer = (t) => t.split(' ');
29
-
30
- describe('Global Override System', () => {
31
- beforeEach(() => {
32
- // Reset models and overrides before each test
33
- modelService.models = {};
34
- modelService.clearGlobalOverride(); // Clear all overrides
35
- modelService.bestPublicModelKey = 'fastGood';
36
-
37
- // Setup basic models for testing
38
- modelService.models = {
39
- fastGood: new Model({
40
- name: 'gpt-4-fast-good',
41
- maxContextWindow: 128000,
42
- maxOutputTokens: 16384,
43
- requestTimeout: 1000,
44
- apiUrl: 'https://api.openai.com',
45
- apiKey: 'test-key',
46
- endpoint: '/v1/chat/completions',
47
- tokenizer,
48
- }),
49
- fastCheap: new Model({
50
- name: 'gpt-4-fast-cheap',
51
- maxContextWindow: 128000,
52
- maxOutputTokens: 8192,
53
- requestTimeout: 1000,
54
- apiUrl: 'https://api.openai.com',
55
- apiKey: 'test-key',
56
- endpoint: '/v1/chat/completions',
57
- tokenizer,
58
- }),
59
- fastCheapReasoning: new Model({
60
- name: 'gpt-4-fast-cheap-reasoning',
61
- maxContextWindow: 200000,
62
- maxOutputTokens: 50000,
63
- requestTimeout: 3000,
64
- apiUrl: 'https://api.openai.com',
65
- apiKey: 'reasoning-key',
66
- endpoint: '/v1/chat/completions',
67
- tokenizer,
68
- }),
69
- customModel: new Model({
70
- name: 'custom-model-name',
71
- maxContextWindow: 64000,
72
- maxOutputTokens: 8192,
73
- requestTimeout: 2000,
74
- apiUrl: 'https://custom.api.com',
75
- apiKey: 'custom-key',
76
- endpoint: '/v1/completions',
77
- tokenizer,
78
- }),
79
- expensiveReasoning: new Model({
80
- name: 'gpt-4-reasoning',
81
- maxContextWindow: 200000,
82
- maxOutputTokens: 100000,
83
- requestTimeout: 5000,
84
- apiUrl: 'https://api.openai.com',
85
- apiKey: 'reasoning-key',
86
- endpoint: '/v1/chat/completions',
87
- tokenizer,
88
- }),
89
- fastReasoning: new Model({
90
- name: 'gpt-4-fast-reasoning',
91
- maxContextWindow: 200000,
92
- maxOutputTokens: 50000,
93
- requestTimeout: 3000,
94
- apiUrl: 'https://api.openai.com',
95
- apiKey: 'reasoning-key',
96
- endpoint: '/v1/chat/completions',
97
- tokenizer,
98
- }),
99
- };
100
-
101
- // Reset and setup fetch mock for each test
102
- vi.clearAllMocks();
103
- fetch.mockResolvedValue({
104
- ok: true,
105
- status: 200,
106
- json: () =>
107
- Promise.resolve({
108
- choices: [{ message: { content: 'Test response' } }],
109
- }),
110
- });
111
- });
112
-
113
- afterEach(() => {
114
- vi.clearAllMocks();
115
- modelService.clearGlobalOverride(); // Clean up after each test
116
- });
117
-
118
- describe('Global Override Management', () => {
119
- it('should set and get global overrides', () => {
120
- modelService.setGlobalOverride('modelName', 'customModel');
121
- modelService.setGlobalOverride('temperature', 0.8);
122
-
123
- expect(modelService.getGlobalOverride('modelName')).toBe('customModel');
124
- expect(modelService.getGlobalOverride('temperature')).toBe(0.8);
125
- expect(modelService.getGlobalOverride('maxTokens')).toBe(null);
126
- });
127
-
128
- it('should get all global overrides', () => {
129
- modelService.setGlobalOverride('modelName', 'customModel');
130
- modelService.setGlobalOverride('temperature', 0.8);
131
-
132
- const allOverrides = modelService.getAllGlobalOverrides();
133
- expect(allOverrides.modelName).toBe('customModel');
134
- expect(allOverrides.temperature).toBe(0.8);
135
- expect(allOverrides.maxTokens).toBe(null);
136
- });
137
-
138
- it('should clear specific global overrides', () => {
139
- modelService.setGlobalOverride('modelName', 'customModel');
140
- modelService.setGlobalOverride('temperature', 0.8);
141
-
142
- modelService.clearGlobalOverride('modelName');
143
-
144
- expect(modelService.getGlobalOverride('modelName')).toBe(null);
145
- expect(modelService.getGlobalOverride('temperature')).toBe(0.8);
146
- });
147
-
148
- it('should clear all global overrides', () => {
149
- modelService.setGlobalOverride('modelName', 'customModel');
150
- modelService.setGlobalOverride('temperature', 0.8);
151
-
152
- modelService.clearGlobalOverride();
153
-
154
- expect(modelService.getGlobalOverride('modelName')).toBe(null);
155
- expect(modelService.getGlobalOverride('temperature')).toBe(null);
156
- });
157
-
158
- it('should throw error for invalid override keys', () => {
159
- expect(() => {
160
- modelService.setGlobalOverride('invalidKey', 'value');
161
- }).toThrow('Invalid override key: invalidKey');
162
-
163
- expect(() => {
164
- modelService.clearGlobalOverride('invalidKey');
165
- }).toThrow('Invalid override key: invalidKey');
166
- });
167
- });
168
-
169
- describe('Model Name Override', () => {
170
- it('should override model selection globally', async () => {
171
- // Set global model override
172
- modelService.setGlobalOverride('modelName', 'customModel');
173
-
174
- const result = await chatgptRun('Test prompt', {
175
- modelOptions: {
176
- modelName: 'fastGood', // This should be overridden
177
- },
178
- });
179
-
180
- expect(result).toBe('Test response');
181
- expect(fetch).toHaveBeenCalledWith(
182
- 'https://custom.api.com/v1/completions',
183
- expect.objectContaining({
184
- headers: {
185
- Authorization: 'Bearer custom-key',
186
- 'Content-Type': 'application/json',
187
- },
188
- body: expect.stringContaining('"model":"custom-model-name"'),
189
- })
190
- );
191
- });
192
-
193
- it('should override even when no modelOptions provided', async () => {
194
- modelService.setGlobalOverride('modelName', 'expensiveReasoning');
195
-
196
- const result = await chatgptRun('Test prompt');
197
-
198
- expect(result).toBe('Test response');
199
- expect(fetch).toHaveBeenCalledWith(
200
- 'https://api.openai.com/v1/chat/completions',
201
- expect.objectContaining({
202
- headers: {
203
- Authorization: 'Bearer reasoning-key',
204
- 'Content-Type': 'application/json',
205
- },
206
- body: expect.stringContaining('"model":"gpt-4-reasoning"'),
207
- })
208
- );
209
- });
210
- });
211
-
212
- describe('Negotiation Override', () => {
213
- it('should override negotiation options globally', async () => {
214
- modelService.setGlobalOverride('negotiate', { reasoning: true });
215
-
216
- const result = await chatgptRun('Test prompt', {
217
- modelOptions: {
218
- modelName: 'fastGood',
219
- negotiate: { fast: true, cheap: true }, // This should be overridden
220
- },
221
- });
222
-
223
- expect(result).toBe('Test response');
224
- // Should negotiate to reasoning model instead of fast+cheap
225
- expect(fetch).toHaveBeenCalledWith(
226
- 'https://api.openai.com/v1/chat/completions',
227
- expect.objectContaining({
228
- body: expect.stringContaining('"model":"gpt-4-fast-cheap-reasoning"'),
229
- })
230
- );
231
- });
232
-
233
- it('should apply negotiation when none provided in options', async () => {
234
- modelService.setGlobalOverride('negotiate', { fast: true, cheap: true });
235
-
236
- const result = await chatgptRun('Test prompt', {
237
- modelOptions: {
238
- modelName: 'expensiveReasoning', // Should be overridden by negotiation
239
- },
240
- });
241
-
242
- expect(result).toBe('Test response');
243
- // Should negotiate instead of using explicit model
244
- expect(fetch).toHaveBeenCalledWith(
245
- 'https://api.openai.com/v1/chat/completions',
246
- expect.objectContaining({
247
- body: expect.stringContaining('"model":"gpt-4-fast-cheap"'),
248
- })
249
- );
250
- });
251
- });
252
-
253
- describe('Parameter Overrides', () => {
254
- it('should override temperature globally', async () => {
255
- modelService.setGlobalOverride('temperature', 0.9);
256
-
257
- const result = await chatgptRun('Test prompt', {
258
- modelOptions: {
259
- modelName: 'fastGood',
260
- temperature: 0.1, // This should be overridden
261
- },
262
- });
263
-
264
- expect(result).toBe('Test response');
265
- expect(fetch).toHaveBeenCalledWith(
266
- 'https://api.openai.com/v1/chat/completions',
267
- expect.objectContaining({
268
- body: expect.stringContaining('"temperature":0.9'),
269
- })
270
- );
271
- });
272
-
273
- it('should override multiple parameters', async () => {
274
- modelService.setGlobalOverride('temperature', 0.8);
275
- modelService.setGlobalOverride('maxTokens', 1500);
276
- modelService.setGlobalOverride('topP', 0.95);
277
-
278
- const result = await chatgptRun('Test prompt', {
279
- modelOptions: {
280
- modelName: 'fastGood',
281
- temperature: 0.1,
282
- maxTokens: 500,
283
- topP: 0.5,
284
- },
285
- });
286
-
287
- expect(result).toBe('Test response');
288
-
289
- const requestBody = JSON.parse(fetch.mock.calls[0][1].body);
290
- expect(requestBody.temperature).toBe(0.8);
291
- expect(requestBody.max_tokens).toBe(1500);
292
- expect(requestBody.top_p).toBe(0.95);
293
- });
294
-
295
- it('should preserve non-overridden parameters', async () => {
296
- modelService.setGlobalOverride('temperature', 0.8);
297
-
298
- const result = await chatgptRun('Test prompt', {
299
- modelOptions: {
300
- modelName: 'fastGood',
301
- temperature: 0.1,
302
- maxTokens: 2000,
303
- topP: 0.7,
304
- },
305
- });
306
-
307
- expect(result).toBe('Test response');
308
-
309
- const requestBody = JSON.parse(fetch.mock.calls[0][1].body);
310
- expect(requestBody.temperature).toBe(0.8); // Overridden
311
- expect(requestBody.max_tokens).toBe(2000); // Preserved
312
- expect(requestBody.top_p).toBe(0.7); // Preserved
313
- });
314
- });
315
-
316
- describe('Complex Override Scenarios', () => {
317
- it('should combine model and parameter overrides', async () => {
318
- modelService.setGlobalOverride('modelName', 'customModel');
319
- modelService.setGlobalOverride('temperature', 0.9);
320
-
321
- const result = await chatgptRun('Test prompt', {
322
- modelOptions: {
323
- modelName: 'fastGood',
324
- temperature: 0.1,
325
- maxTokens: 1000,
326
- },
327
- });
328
-
329
- expect(result).toBe('Test response');
330
- expect(fetch).toHaveBeenCalledWith(
331
- 'https://custom.api.com/v1/completions',
332
- expect.objectContaining({
333
- headers: {
334
- Authorization: 'Bearer custom-key',
335
- 'Content-Type': 'application/json',
336
- },
337
- body: expect.stringContaining('"temperature":0.9'),
338
- })
339
- );
340
-
341
- const requestBody = JSON.parse(fetch.mock.calls[0][1].body);
342
- expect(requestBody.model).toBe('custom-model-name');
343
- expect(requestBody.max_tokens).toBe(1000); // Preserved
344
- });
345
-
346
- it('should handle override precedence correctly', async () => {
347
- // Set both model name and negotiation overrides
348
- modelService.setGlobalOverride('modelName', 'customModel');
349
- modelService.setGlobalOverride('negotiate', { reasoning: true });
350
-
351
- const result = await chatgptRun('Test prompt', {
352
- modelOptions: {
353
- modelName: 'fastGood',
354
- },
355
- });
356
-
357
- expect(result).toBe('Test response');
358
- // Negotiation should take precedence and override the model name
359
- expect(fetch).toHaveBeenCalledWith(
360
- 'https://api.openai.com/v1/chat/completions',
361
- expect.objectContaining({
362
- body: expect.stringContaining('"model":"gpt-4-fast-cheap-reasoning"'),
363
- })
364
- );
365
- });
366
-
367
- it('should work with empty modelOptions', async () => {
368
- modelService.setGlobalOverride('modelName', 'customModel');
369
- modelService.setGlobalOverride('temperature', 0.7);
370
-
371
- const result = await chatgptRun('Test prompt');
372
-
373
- expect(result).toBe('Test response');
374
- expect(fetch).toHaveBeenCalledWith(
375
- 'https://custom.api.com/v1/completions',
376
- expect.objectContaining({
377
- headers: {
378
- Authorization: 'Bearer custom-key',
379
- 'Content-Type': 'application/json',
380
- },
381
- body: expect.stringContaining('"temperature":0.7'),
382
- })
383
- );
384
- });
385
- });
386
-
387
- describe('Override Isolation', () => {
388
- it('should not affect subsequent calls after clearing overrides', async () => {
389
- // Set override and make a call
390
- modelService.setGlobalOverride('modelName', 'customModel');
391
-
392
- await chatgptRun('Test prompt 1');
393
- expect(fetch).toHaveBeenCalledWith(
394
- 'https://custom.api.com/v1/completions',
395
- expect.anything()
396
- );
397
-
398
- // Clear override and make another call
399
- modelService.clearGlobalOverride('modelName');
400
- fetch.mockClear();
401
-
402
- await chatgptRun('Test prompt 2');
403
- expect(fetch).toHaveBeenCalledWith(
404
- 'https://api.openai.com/v1/chat/completions',
405
- expect.anything()
406
- );
407
- });
408
-
409
- it('should apply overrides consistently across multiple calls', async () => {
410
- modelService.setGlobalOverride('temperature', 0.8);
411
-
412
- // First call
413
- await chatgptRun('Test prompt 1', {
414
- modelOptions: { modelName: 'fastGood', temperature: 0.1 },
415
- });
416
-
417
- // Second call
418
- await chatgptRun('Test prompt 2', {
419
- modelOptions: { modelName: 'customModel', temperature: 0.2 },
420
- });
421
-
422
- // Both calls should have temperature overridden to 0.8
423
- expect(fetch).toHaveBeenCalledTimes(2);
424
-
425
- const firstCall = JSON.parse(fetch.mock.calls[0][1].body);
426
- const secondCall = JSON.parse(fetch.mock.calls[1][1].body);
427
-
428
- expect(firstCall.temperature).toBe(0.8);
429
- expect(secondCall.temperature).toBe(0.8);
430
- });
431
- });
432
- });