@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
@@ -0,0 +1,460 @@
1
+ # Ring Buffer
2
+
3
+ A memory-efficient circular buffer designed for high-throughput logging, batch processing, and LLM operations. Automatically evicts oldest entries when full, making it ideal for streaming data scenarios where memory efficiency is critical.
4
+
5
+ ## Features
6
+
7
+ - **Automatic Memory Management**: Configurable size limits with automatic eviction of oldest entries
8
+ - **Multiple Cursor Support**: Track multiple processing positions concurrently
9
+ - **Batch Operations**: Optimized for LLM workflows with parallel and sequential processing
10
+ - **Flexible Access Patterns**: ID-based, index-based, and time-based slicing
11
+ - **Rich Query Interface**: Filter, find, map, and reduce operations
12
+ - **Iterator Support**: Works with for...of loops and spread operator
13
+ - **Statistics Tracking**: Monitor buffer usage and performance metrics
14
+
15
+ ## Basic Usage
16
+
17
+ ```javascript
18
+ import RingBuffer from '../lib/ring-buffer/index.js';
19
+
20
+ // Create buffer with capacity of 1000 entries
21
+ const buffer = new RingBuffer(1000);
22
+
23
+ // Add entries
24
+ const entry1 = buffer.push('Hello world');
25
+ const entry2 = buffer.push({ user: 'alice', action: 'login' });
26
+
27
+ // Get all entries
28
+ const allEntries = buffer.all();
29
+ console.log(`Buffer contains ${allEntries.length} entries`);
30
+
31
+ // Add metadata
32
+ const meta = new Map([['source', 'api'], ['priority', 'high']]);
33
+ buffer.push('Important message', meta);
34
+ ```
35
+
36
+ ## Batch Operations
37
+
38
+ Perfect for processing large datasets in manageable chunks:
39
+
40
+ ```javascript
41
+ // Add multiple entries at once
42
+ const logData = ['error 1', 'error 2', 'error 3'];
43
+ const entries = buffer.pushBatch(logData);
44
+
45
+ // Process in batches
46
+ await buffer.processBatches(50, async (batch, batchIndex) => {
47
+ console.log(`Processing batch ${batchIndex} with ${batch.length} entries`);
48
+
49
+ // Your processing logic here
50
+ const results = await processLogBatch(batch);
51
+ return results;
52
+ });
53
+
54
+ // Parallel processing for better performance
55
+ await buffer.processBatches(25, processBatch, { parallel: true });
56
+ ```
57
+
58
+ ## Cursor Operations
59
+
60
+ Track multiple processing positions for concurrent operations:
61
+
62
+ ```javascript
63
+ // Create cursors for different processors
64
+ buffer.setCursor('error-processor', 0);
65
+ buffer.setCursor('audit-processor', 0);
66
+ buffer.setCursor('analytics-processor', 0);
67
+
68
+ // Process new entries since last cursor position
69
+ const newErrors = buffer.getSinceCursor('error-processor');
70
+ console.log(`Found ${newErrors.length} new entries to process`);
71
+
72
+ // Cursor automatically moves to latest processed position
73
+ // Or control cursor movement manually
74
+ const entries = buffer.getSinceCursor('audit-processor', false); // Don't move cursor
75
+ ```
76
+
77
+ ## Flexible Querying
78
+
79
+ Rich query interface for finding and analyzing data:
80
+
81
+ ```javascript
82
+ // Find entries matching criteria
83
+ const errors = buffer.filter(entry =>
84
+ typeof entry.data === 'string' && entry.data.includes('ERROR')
85
+ );
86
+
87
+ // Find first match
88
+ const criticalError = buffer.find(entry =>
89
+ entry.meta.get('priority') === 'critical'
90
+ );
91
+
92
+ // Transform data
93
+ const timestamps = buffer.map(entry => entry.timestamp);
94
+
95
+ // Aggregate data
96
+ const totalSize = buffer.reduce((sum, entry) =>
97
+ sum + JSON.stringify(entry.data).length, 0
98
+ );
99
+ ```
100
+
101
+ ## Slicing Operations
102
+
103
+ Access data using different strategies:
104
+
105
+ ```javascript
106
+ // Get entries by ID range
107
+ const recentEntries = buffer.slice(1000, 1100);
108
+
109
+ // Get entries by index (like Array.slice)
110
+ const firstTen = buffer.sliceByIndex(0, 10);
111
+ const lastTen = buffer.tail(10);
112
+
113
+ // Get entries by time range
114
+ const lastHour = new Date(Date.now() - 3600000);
115
+ const recentLogs = buffer.sliceByTime(lastHour);
116
+ ```
117
+
118
+ ## Memory Management
119
+
120
+ Automatic memory management with detailed statistics:
121
+
122
+ ```javascript
123
+ // Check buffer status
124
+ console.log(`Buffer is ${buffer.isFull() ? 'full' : 'not full'}`);
125
+ console.log(`Current size: ${buffer.size()}/${buffer.capacity()}`);
126
+
127
+ // Get detailed statistics
128
+ const stats = buffer.getStats();
129
+ console.log(`Total added: ${stats.totalAdded}`);
130
+ console.log(`Total evicted: ${stats.totalEvicted}`);
131
+ console.log(`Active cursors: ${stats.cursors}`);
132
+
133
+ // Clear buffer when needed
134
+ buffer.clear(); // Removes all entries and cursors
135
+ buffer.clear(true); // Keeps cursors, removes entries
136
+ ```
137
+
138
+ ## LLM Chain Integration
139
+
140
+ Designed specifically for LLM workflows:
141
+
142
+ ```javascript
143
+ // Log processing pipeline
144
+ const logBuffer = new RingBuffer(5000);
145
+
146
+ // Add logs from various sources
147
+ logBuffer.push('User query: "What is the weather?"');
148
+ logBuffer.push({ type: 'llm-request', model: 'gpt-4', tokens: 150 });
149
+ logBuffer.push('LLM response: "The weather is sunny..."');
150
+
151
+ // Process logs in batches for LLM analysis
152
+ await logBuffer.processBatches(100, async (batch) => {
153
+ // Send batch to LLM for analysis
154
+ const analysis = await analyzeLogs(batch);
155
+ return analysis;
156
+ });
157
+
158
+ // Track different processing stages
159
+ logBuffer.setCursor('preprocessing', 0);
160
+ logBuffer.setCursor('llm-analysis', 0);
161
+ logBuffer.setCursor('postprocessing', 0);
162
+
163
+ // Each stage processes from its cursor position
164
+ const toPreprocess = logBuffer.getSinceCursor('preprocessing');
165
+ const toAnalyze = logBuffer.getSinceCursor('llm-analysis');
166
+ ```
167
+
168
+ ## Advanced Features
169
+
170
+ ### Iterator Support
171
+
172
+ ```javascript
173
+ // Use with for...of loops
174
+ for (const entry of buffer) {
175
+ console.log(`Entry ${entry.id}: ${entry.data}`);
176
+ }
177
+
178
+ // Use with spread operator
179
+ const allEntries = [...buffer];
180
+ ```
181
+
182
+ ### Filtered Buffers
183
+
184
+ ```javascript
185
+ // Create new buffer with filtered data
186
+ const errorBuffer = buffer.createFiltered(
187
+ entry => entry.data.includes('ERROR'),
188
+ 500 // New buffer capacity
189
+ );
190
+ ```
191
+
192
+ ### Cursor Metadata
193
+
194
+ ```javascript
195
+ const cursor = buffer.setCursor('processor-1');
196
+ cursor.meta.set('owner', 'error-handler');
197
+ cursor.meta.set('last-processed', new Date());
198
+ ```
199
+
200
+ ## Performance Characteristics
201
+
202
+ - **Memory**: O(n) where n is buffer capacity (not total entries added)
203
+ - **Push**: O(1) amortized
204
+ - **Slice by ID**: O(n) where n is buffer size
205
+ - **Slice by Index**: O(k) where k is slice size
206
+ - **Cursor Operations**: O(1) for cursor management, O(n) for getSinceCursor
207
+
208
+ ## Use Cases
209
+
210
+ - **High-throughput Logging**: Capture logs without memory leaks
211
+ - **LLM Chain Processing**: Batch operations on conversation history
212
+ - **Stream Processing**: Process data streams with multiple consumers
213
+ - **Audit Trails**: Maintain recent activity with automatic cleanup
214
+ - **Performance Monitoring**: Track metrics with bounded memory usage
215
+ - **Event Sourcing**: Store recent events with cursor-based replay
216
+
217
+ The ring buffer is particularly valuable in LLM applications where you need to maintain context windows, process conversation history in batches, or implement streaming responses with memory constraints.
218
+
219
+ ## Stable Batch Processing
220
+
221
+ The ring buffer provides advanced stable batch processing capabilities that maintain consistent batch boundaries even when the buffer window changes due to eviction. This is essential for reliable retry scenarios and parallel processing.
222
+
223
+ ### Key Features
224
+
225
+ - **Globally Stable Batches**: Batch definitions based on entry IDs (not indices) remain consistent
226
+ - **Cursor-Based Iteration**: Multiple cursors can iterate over identical batch boundaries
227
+ - **Built-in Retry Logic**: Configurable retry with exponential backoff
228
+ - **Parallel Processing**: Process batches concurrently while maintaining stability
229
+ - **Resume Capability**: Resume processing from exact batch boundaries after interruption
230
+
231
+ ### Basic Stable Batch Processing
232
+
233
+ ```javascript
234
+ const buffer = new RingBuffer(1000);
235
+
236
+ // Add data
237
+ for (let i = 1; i <= 100; i++) {
238
+ buffer.push({ id: i, data: `item-${i}` });
239
+ }
240
+
241
+ // Process in stable batches with retry
242
+ const results = await buffer.processStableBatches(10, async (entries, batchDef, context) => {
243
+ console.log(`Processing ${batchDef.batchId}: ${entries.length} entries`);
244
+
245
+ // Your processing logic here
246
+ return entries.map(entry => entry.data.toUpperCase());
247
+ }, {
248
+ maxRetries: 3,
249
+ retryDelay: (attempt) => 1000 * Math.pow(2, attempt), // Exponential backoff
250
+ parallel: false, // Sequential processing
251
+ onBatchStart: (batchDef) => console.log(`Starting ${batchDef.batchId}`),
252
+ onBatchComplete: (batchDef, result) => console.log(`Completed ${batchDef.batchId}`),
253
+ onBatchError: (batchDef, error, attempt) => console.log(`Error in ${batchDef.batchId}: ${error.message}`)
254
+ });
255
+ ```
256
+
257
+ ### Resumable Processing with Cursors
258
+
259
+ ```javascript
260
+ // First processing run
261
+ try {
262
+ await buffer.processStableBatches(5, processor, {
263
+ cursorName: 'main-processor',
264
+ maxRetries: 2
265
+ });
266
+ } catch (error) {
267
+ console.log('Processing interrupted:', error.message);
268
+ }
269
+
270
+ // Resume from where we left off
271
+ const resumeResults = await buffer.processStableBatches(5, processor, {
272
+ cursorName: 'main-processor' // Automatically resumes from cursor position
273
+ });
274
+ ```
275
+
276
+ ### Parallel Processing with Synchronized Cursors
277
+
278
+ ```javascript
279
+ // Create synchronized cursors for multiple workers
280
+ const workers = buffer.createSynchronizedBatchCursors(
281
+ ['worker-1', 'worker-2', 'worker-3'],
282
+ 20 // batch size
283
+ );
284
+
285
+ // Each worker processes different batches but with identical boundaries
286
+ const results = await Promise.all([
287
+ processWorkerBatches(workers['worker-1']),
288
+ processWorkerBatches(workers['worker-2']),
289
+ processWorkerBatches(workers['worker-3'])
290
+ ]);
291
+
292
+ async function processWorkerBatches(worker) {
293
+ const results = [];
294
+ while (true) {
295
+ const batch = worker.next();
296
+ if (batch.done) break;
297
+
298
+ // Process this batch
299
+ const result = await processBatch(batch.entries);
300
+ results.push({ batchId: batch.batchDef.batchId, result });
301
+ }
302
+ return results;
303
+ }
304
+ ```
305
+
306
+ ### Batch Cursor Iteration
307
+
308
+ ```javascript
309
+ // Create a batch cursor for manual iteration
310
+ const cursor = buffer.createBatchCursor('manual-cursor', 15);
311
+
312
+ while (true) {
313
+ const batch = cursor.next();
314
+ if (batch.done) break;
315
+
316
+ console.log(`Processing batch ${batch.batchDef.batchId}`);
317
+ console.log(` Entries: ${batch.entries.length}`);
318
+ console.log(` ID range: ${batch.batchDef.startId}-${batch.batchDef.endId - 1}`);
319
+
320
+ // Process entries
321
+ await processEntries(batch.entries);
322
+ }
323
+
324
+ // Check cursor status
325
+ const status = cursor.getStatus();
326
+ console.log(`Processed batches, ${status.remainingEntries} entries remaining`);
327
+ ```
328
+
329
+ ### Integration with External Retry Libraries
330
+
331
+ ```javascript
332
+ import retry from 'your-retry-library';
333
+
334
+ // Wrap your processor with external retry logic
335
+ const retryProcessor = async (entries, batchDef, context) => {
336
+ return await retry(async () => {
337
+ // Your processing logic that might fail
338
+ return await processEntries(entries);
339
+ }, {
340
+ retries: 3,
341
+ factor: 2
342
+ });
343
+ };
344
+
345
+ // Use with stable batch processing (no built-in retry needed)
346
+ const results = await buffer.processStableBatches(10, retryProcessor, {
347
+ maxRetries: 0 // Disable built-in retry since we're using external
348
+ });
349
+ ```
350
+
351
+ ### Handling Missing Entries (Eviction)
352
+
353
+ ```javascript
354
+ // Small buffer that will evict entries
355
+ const smallBuffer = new RingBuffer(50);
356
+
357
+ // Add lots of data to force eviction
358
+ for (let i = 1; i <= 100; i++) {
359
+ smallBuffer.push(`item-${i}`);
360
+ }
361
+
362
+ // Process with missing entry handling
363
+ const results = await smallBuffer.processStableBatches(10, processor, {
364
+ startId: 1, // Some of these entries may be evicted
365
+ skipMissingEntries: true // Skip batches with no available entries
366
+ });
367
+
368
+ // Check which batches were skipped
369
+ results.forEach(result => {
370
+ if (result.skipped) {
371
+ console.log(`Batch ${result.batchId} was skipped (entries evicted)`);
372
+ }
373
+ });
374
+ ```
375
+
376
+ ### Advanced Configuration
377
+
378
+ ```javascript
379
+ const results = await buffer.processStableBatches(batchSize, processor, {
380
+ // Cursor tracking
381
+ cursorName: 'my-processor', // Track progress with named cursor
382
+
383
+ // Range control
384
+ startId: 100, // Start from specific entry ID
385
+ endId: 500, // End at specific entry ID
386
+
387
+ // Processing mode
388
+ parallel: true, // Process batches in parallel
389
+
390
+ // Retry configuration
391
+ maxRetries: 5, // Maximum retry attempts per batch
392
+ retryDelay: (attempt) => 1000 * attempt, // Custom delay function
393
+
394
+ // Missing entry handling
395
+ skipMissingEntries: true, // Skip batches with evicted entries
396
+
397
+ // Event callbacks
398
+ onBatchStart: (batchDef) => {
399
+ console.log(`Starting ${batchDef.batchId}`);
400
+ },
401
+ onBatchComplete: (batchDef, result) => {
402
+ console.log(`Completed ${batchDef.batchId}`);
403
+ },
404
+ onBatchError: (batchDef, error, attempt) => {
405
+ console.log(`Error in ${batchDef.batchId} (attempt ${attempt}): ${error.message}`);
406
+ }
407
+ });
408
+ ```
409
+
410
+ ### Stable Batch Definitions
411
+
412
+ ```javascript
413
+ // Create stable batch definitions without processing
414
+ const batchDefs = buffer.createStableBatches(10, {
415
+ startId: 50,
416
+ endId: 150,
417
+ batchIdPrefix: 'custom'
418
+ });
419
+
420
+ console.log(`Created ${batchDefs.length} stable batches`);
421
+
422
+ // Later, get entries for a specific batch
423
+ const entries = buffer.getBatchEntries(batchDefs[0]);
424
+ console.log(`Batch ${batchDefs[0].batchId} has ${entries.length} available entries`);
425
+ ```
426
+
427
+ ### Use Cases
428
+
429
+ **Data Pipeline Processing**: Process large datasets in reliable, resumable batches
430
+ ```javascript
431
+ await buffer.processStableBatches(100, async (entries) => {
432
+ return await sendToAPI(entries);
433
+ }, { cursorName: 'pipeline', maxRetries: 3 });
434
+ ```
435
+
436
+ **Parallel Worker Processing**: Multiple workers processing different batches
437
+ ```javascript
438
+ const workers = buffer.createSynchronizedBatchCursors(['w1', 'w2', 'w3'], 50);
439
+ // Each worker gets identical batch boundaries for consistent processing
440
+ ```
441
+
442
+ **Fault-Tolerant Batch Jobs**: Resume exactly where processing was interrupted
443
+ ```javascript
444
+ // Job can be interrupted and resumed with identical batch boundaries
445
+ await buffer.processStableBatches(25, processor, {
446
+ cursorName: 'batch-job',
447
+ maxRetries: 5
448
+ });
449
+ ```
450
+
451
+ **Memory-Efficient Stream Processing**: Process continuous data streams in batches
452
+ ```javascript
453
+ const cursor = buffer.createBatchCursor('stream', 20);
454
+ setInterval(async () => {
455
+ const batch = cursor.next();
456
+ if (!batch.done) {
457
+ await processStreamBatch(batch.entries);
458
+ }
459
+ }, 1000);
460
+ ```