@indigoai-us/cq 0.0.1

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 (177) hide show
  1. package/dist/__tests__/integration.test.d.ts +8 -0
  2. package/dist/__tests__/integration.test.d.ts.map +1 -0
  3. package/dist/__tests__/integration.test.js +233 -0
  4. package/dist/__tests__/integration.test.js.map +1 -0
  5. package/dist/budget/__tests__/budget.test.d.ts +2 -0
  6. package/dist/budget/__tests__/budget.test.d.ts.map +1 -0
  7. package/dist/budget/__tests__/budget.test.js +238 -0
  8. package/dist/budget/__tests__/budget.test.js.map +1 -0
  9. package/dist/budget/__tests__/token-tracker.test.d.ts +2 -0
  10. package/dist/budget/__tests__/token-tracker.test.d.ts.map +1 -0
  11. package/dist/budget/__tests__/token-tracker.test.js +292 -0
  12. package/dist/budget/__tests__/token-tracker.test.js.map +1 -0
  13. package/dist/budget/index.d.ts +38 -0
  14. package/dist/budget/index.d.ts.map +1 -0
  15. package/dist/budget/index.js +192 -0
  16. package/dist/budget/index.js.map +1 -0
  17. package/dist/budget/token-tracker.d.ts +62 -0
  18. package/dist/budget/token-tracker.d.ts.map +1 -0
  19. package/dist/budget/token-tracker.js +152 -0
  20. package/dist/budget/token-tracker.js.map +1 -0
  21. package/dist/budget/types.d.ts +41 -0
  22. package/dist/budget/types.d.ts.map +1 -0
  23. package/dist/budget/types.js +5 -0
  24. package/dist/budget/types.js.map +1 -0
  25. package/dist/confidence/__tests__/confidence.test.d.ts +2 -0
  26. package/dist/confidence/__tests__/confidence.test.d.ts.map +1 -0
  27. package/dist/confidence/__tests__/confidence.test.js +336 -0
  28. package/dist/confidence/__tests__/confidence.test.js.map +1 -0
  29. package/dist/confidence/erosion.d.ts +33 -0
  30. package/dist/confidence/erosion.d.ts.map +1 -0
  31. package/dist/confidence/erosion.js +42 -0
  32. package/dist/confidence/erosion.js.map +1 -0
  33. package/dist/confidence/index.d.ts +42 -0
  34. package/dist/confidence/index.d.ts.map +1 -0
  35. package/dist/confidence/index.js +168 -0
  36. package/dist/confidence/index.js.map +1 -0
  37. package/dist/confidence/types.d.ts +29 -0
  38. package/dist/confidence/types.d.ts.map +1 -0
  39. package/dist/confidence/types.js +5 -0
  40. package/dist/confidence/types.js.map +1 -0
  41. package/dist/curiosity/__tests__/curiosity.test.d.ts +2 -0
  42. package/dist/curiosity/__tests__/curiosity.test.d.ts.map +1 -0
  43. package/dist/curiosity/__tests__/curiosity.test.js +280 -0
  44. package/dist/curiosity/__tests__/curiosity.test.js.map +1 -0
  45. package/dist/curiosity/dedup.d.ts +29 -0
  46. package/dist/curiosity/dedup.d.ts.map +1 -0
  47. package/dist/curiosity/dedup.js +64 -0
  48. package/dist/curiosity/dedup.js.map +1 -0
  49. package/dist/curiosity/index.d.ts +56 -0
  50. package/dist/curiosity/index.d.ts.map +1 -0
  51. package/dist/curiosity/index.js +163 -0
  52. package/dist/curiosity/index.js.map +1 -0
  53. package/dist/curiosity/types.d.ts +29 -0
  54. package/dist/curiosity/types.d.ts.map +1 -0
  55. package/dist/curiosity/types.js +5 -0
  56. package/dist/curiosity/types.js.map +1 -0
  57. package/dist/index.d.ts +25 -0
  58. package/dist/index.d.ts.map +1 -0
  59. package/dist/index.js +16 -0
  60. package/dist/index.js.map +1 -0
  61. package/dist/index.test.d.ts +2 -0
  62. package/dist/index.test.d.ts.map +1 -0
  63. package/dist/index.test.js +7 -0
  64. package/dist/index.test.js.map +1 -0
  65. package/dist/init.d.ts +17 -0
  66. package/dist/init.d.ts.map +1 -0
  67. package/dist/init.js +153 -0
  68. package/dist/init.js.map +1 -0
  69. package/dist/knowledge-tree/__tests__/knowledge-tree.test.d.ts +2 -0
  70. package/dist/knowledge-tree/__tests__/knowledge-tree.test.d.ts.map +1 -0
  71. package/dist/knowledge-tree/__tests__/knowledge-tree.test.js +317 -0
  72. package/dist/knowledge-tree/__tests__/knowledge-tree.test.js.map +1 -0
  73. package/dist/knowledge-tree/format.d.ts +17 -0
  74. package/dist/knowledge-tree/format.d.ts.map +1 -0
  75. package/dist/knowledge-tree/format.js +48 -0
  76. package/dist/knowledge-tree/format.js.map +1 -0
  77. package/dist/knowledge-tree/index.d.ts +33 -0
  78. package/dist/knowledge-tree/index.d.ts.map +1 -0
  79. package/dist/knowledge-tree/index.js +182 -0
  80. package/dist/knowledge-tree/index.js.map +1 -0
  81. package/dist/knowledge-tree/types.d.ts +37 -0
  82. package/dist/knowledge-tree/types.d.ts.map +1 -0
  83. package/dist/knowledge-tree/types.js +5 -0
  84. package/dist/knowledge-tree/types.js.map +1 -0
  85. package/dist/metadata/__tests__/metadata.test.d.ts +2 -0
  86. package/dist/metadata/__tests__/metadata.test.d.ts.map +1 -0
  87. package/dist/metadata/__tests__/metadata.test.js +196 -0
  88. package/dist/metadata/__tests__/metadata.test.js.map +1 -0
  89. package/dist/metadata/__tests__/search.test.d.ts +2 -0
  90. package/dist/metadata/__tests__/search.test.d.ts.map +1 -0
  91. package/dist/metadata/__tests__/search.test.js +227 -0
  92. package/dist/metadata/__tests__/search.test.js.map +1 -0
  93. package/dist/metadata/index.d.ts +29 -0
  94. package/dist/metadata/index.d.ts.map +1 -0
  95. package/dist/metadata/index.js +108 -0
  96. package/dist/metadata/index.js.map +1 -0
  97. package/dist/metadata/schema.d.ts +8 -0
  98. package/dist/metadata/schema.d.ts.map +1 -0
  99. package/dist/metadata/schema.js +31 -0
  100. package/dist/metadata/schema.js.map +1 -0
  101. package/dist/metadata/search.d.ts +27 -0
  102. package/dist/metadata/search.d.ts.map +1 -0
  103. package/dist/metadata/search.js +57 -0
  104. package/dist/metadata/search.js.map +1 -0
  105. package/dist/metadata/types.d.ts +17 -0
  106. package/dist/metadata/types.d.ts.map +1 -0
  107. package/dist/metadata/types.js +5 -0
  108. package/dist/metadata/types.js.map +1 -0
  109. package/dist/orchestrator/__tests__/orchestrator.test.d.ts +2 -0
  110. package/dist/orchestrator/__tests__/orchestrator.test.d.ts.map +1 -0
  111. package/dist/orchestrator/__tests__/orchestrator.test.js +354 -0
  112. package/dist/orchestrator/__tests__/orchestrator.test.js.map +1 -0
  113. package/dist/orchestrator/index.d.ts +23 -0
  114. package/dist/orchestrator/index.d.ts.map +1 -0
  115. package/dist/orchestrator/index.js +302 -0
  116. package/dist/orchestrator/index.js.map +1 -0
  117. package/dist/orchestrator/scheduler.d.ts +32 -0
  118. package/dist/orchestrator/scheduler.d.ts.map +1 -0
  119. package/dist/orchestrator/scheduler.js +102 -0
  120. package/dist/orchestrator/scheduler.js.map +1 -0
  121. package/dist/orchestrator/types.d.ts +90 -0
  122. package/dist/orchestrator/types.d.ts.map +1 -0
  123. package/dist/orchestrator/types.js +5 -0
  124. package/dist/orchestrator/types.js.map +1 -0
  125. package/dist/pipeline/__tests__/pipeline.test.d.ts +2 -0
  126. package/dist/pipeline/__tests__/pipeline.test.d.ts.map +1 -0
  127. package/dist/pipeline/__tests__/pipeline.test.js +320 -0
  128. package/dist/pipeline/__tests__/pipeline.test.js.map +1 -0
  129. package/dist/pipeline/index.d.ts +23 -0
  130. package/dist/pipeline/index.d.ts.map +1 -0
  131. package/dist/pipeline/index.js +212 -0
  132. package/dist/pipeline/index.js.map +1 -0
  133. package/dist/pipeline/types.d.ts +41 -0
  134. package/dist/pipeline/types.d.ts.map +1 -0
  135. package/dist/pipeline/types.js +5 -0
  136. package/dist/pipeline/types.js.map +1 -0
  137. package/dist/providers/__tests__/providers.test.d.ts +2 -0
  138. package/dist/providers/__tests__/providers.test.d.ts.map +1 -0
  139. package/dist/providers/__tests__/providers.test.js +195 -0
  140. package/dist/providers/__tests__/providers.test.js.map +1 -0
  141. package/dist/providers/claude-model.d.ts +17 -0
  142. package/dist/providers/claude-model.d.ts.map +1 -0
  143. package/dist/providers/claude-model.js +119 -0
  144. package/dist/providers/claude-model.js.map +1 -0
  145. package/dist/providers/index.d.ts +22 -0
  146. package/dist/providers/index.d.ts.map +1 -0
  147. package/dist/providers/index.js +38 -0
  148. package/dist/providers/index.js.map +1 -0
  149. package/dist/providers/openai-search.d.ts +14 -0
  150. package/dist/providers/openai-search.d.ts.map +1 -0
  151. package/dist/providers/openai-search.js +97 -0
  152. package/dist/providers/openai-search.js.map +1 -0
  153. package/dist/providers/types.d.ts +42 -0
  154. package/dist/providers/types.d.ts.map +1 -0
  155. package/dist/providers/types.js +5 -0
  156. package/dist/providers/types.js.map +1 -0
  157. package/dist/types.d.ts +122 -0
  158. package/dist/types.d.ts.map +1 -0
  159. package/dist/types.js +5 -0
  160. package/dist/types.js.map +1 -0
  161. package/dist/vetter/__tests__/vetter.test.d.ts +2 -0
  162. package/dist/vetter/__tests__/vetter.test.d.ts.map +1 -0
  163. package/dist/vetter/__tests__/vetter.test.js +224 -0
  164. package/dist/vetter/__tests__/vetter.test.js.map +1 -0
  165. package/dist/vetter/index.d.ts +23 -0
  166. package/dist/vetter/index.d.ts.map +1 -0
  167. package/dist/vetter/index.js +177 -0
  168. package/dist/vetter/index.js.map +1 -0
  169. package/dist/vetter/resource-tracker.d.ts +49 -0
  170. package/dist/vetter/resource-tracker.d.ts.map +1 -0
  171. package/dist/vetter/resource-tracker.js +183 -0
  172. package/dist/vetter/resource-tracker.js.map +1 -0
  173. package/dist/vetter/types.d.ts +44 -0
  174. package/dist/vetter/types.d.ts.map +1 -0
  175. package/dist/vetter/types.js +5 -0
  176. package/dist/vetter/types.js.map +1 -0
  177. package/package.json +72 -0
@@ -0,0 +1,292 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { TokenTracker, estimateTokens } from "../token-tracker.js";
3
+ // ---------------------------------------------------------------------------
4
+ // Helpers
5
+ // ---------------------------------------------------------------------------
6
+ function makeEntry(overrides) {
7
+ return {
8
+ category: "test",
9
+ slug: "test-entry",
10
+ title: "Test Entry",
11
+ tags: [],
12
+ created: "2026-01-01T00:00:00Z",
13
+ updated: "2026-01-01T00:00:00Z",
14
+ ...overrides,
15
+ };
16
+ }
17
+ /** Create content of a specific token size (approx). */
18
+ function contentOfTokens(tokens) {
19
+ return "x".repeat(tokens * 4);
20
+ }
21
+ // ---------------------------------------------------------------------------
22
+ // estimateTokens
23
+ // ---------------------------------------------------------------------------
24
+ describe("estimateTokens", () => {
25
+ it("estimates ~4 chars per token", () => {
26
+ expect(estimateTokens("")).toBe(0);
27
+ expect(estimateTokens("abcd")).toBe(1);
28
+ expect(estimateTokens("abcde")).toBe(2); // ceil(5/4) = 2
29
+ expect(estimateTokens("a".repeat(100))).toBe(25);
30
+ });
31
+ });
32
+ // ---------------------------------------------------------------------------
33
+ // Constructor
34
+ // ---------------------------------------------------------------------------
35
+ describe("TokenTracker constructor", () => {
36
+ it("accepts a positive maxTokens value", () => {
37
+ const tracker = new TokenTracker(1000);
38
+ expect(tracker.remaining).toBe(1000);
39
+ });
40
+ it("throws for zero maxTokens", () => {
41
+ expect(() => new TokenTracker(0)).toThrow("maxTokens must be a positive number");
42
+ });
43
+ it("throws for negative maxTokens", () => {
44
+ expect(() => new TokenTracker(-1)).toThrow("maxTokens must be a positive number");
45
+ });
46
+ });
47
+ // ---------------------------------------------------------------------------
48
+ // remaining
49
+ // ---------------------------------------------------------------------------
50
+ describe("remaining", () => {
51
+ it("starts at maxTokens", () => {
52
+ const tracker = new TokenTracker(500);
53
+ expect(tracker.remaining).toBe(500);
54
+ });
55
+ it("decreases after reserve", () => {
56
+ const tracker = new TokenTracker(500);
57
+ const entry = makeEntry({ content: contentOfTokens(100) });
58
+ tracker.reserve(entry);
59
+ expect(tracker.remaining).toBe(400);
60
+ });
61
+ });
62
+ // ---------------------------------------------------------------------------
63
+ // wouldFit
64
+ // ---------------------------------------------------------------------------
65
+ describe("wouldFit", () => {
66
+ it("returns true when entry fits", () => {
67
+ const tracker = new TokenTracker(200);
68
+ const entry = makeEntry({ content: contentOfTokens(100) });
69
+ expect(tracker.wouldFit(entry)).toBe(true);
70
+ });
71
+ it("returns true when entry exactly fills remaining budget", () => {
72
+ const tracker = new TokenTracker(100);
73
+ const entry = makeEntry({ content: contentOfTokens(100) });
74
+ expect(tracker.wouldFit(entry)).toBe(true);
75
+ });
76
+ it("returns false when entry exceeds remaining budget", () => {
77
+ const tracker = new TokenTracker(50);
78
+ const entry = makeEntry({ content: contentOfTokens(100) });
79
+ expect(tracker.wouldFit(entry)).toBe(false);
80
+ });
81
+ it("accounts for already-reserved tokens", () => {
82
+ const tracker = new TokenTracker(200);
83
+ const first = makeEntry({ slug: "first", content: contentOfTokens(150) });
84
+ tracker.reserve(first);
85
+ const second = makeEntry({ slug: "second", content: contentOfTokens(100) });
86
+ expect(tracker.wouldFit(second)).toBe(false);
87
+ });
88
+ });
89
+ // ---------------------------------------------------------------------------
90
+ // reserve / release
91
+ // ---------------------------------------------------------------------------
92
+ describe("reserve", () => {
93
+ it("deducts token count from remaining", () => {
94
+ const tracker = new TokenTracker(1000);
95
+ const entry = makeEntry({ content: contentOfTokens(250) });
96
+ tracker.reserve(entry);
97
+ expect(tracker.remaining).toBe(750);
98
+ });
99
+ it("is idempotent for the same entry", () => {
100
+ const tracker = new TokenTracker(1000);
101
+ const entry = makeEntry({ content: contentOfTokens(100) });
102
+ tracker.reserve(entry);
103
+ tracker.reserve(entry); // no-op
104
+ expect(tracker.remaining).toBe(900);
105
+ });
106
+ it("throws when entry exceeds remaining budget", () => {
107
+ const tracker = new TokenTracker(50);
108
+ const entry = makeEntry({ content: contentOfTokens(100) });
109
+ expect(() => tracker.reserve(entry)).toThrow("Cannot reserve 100 tokens");
110
+ });
111
+ it("tracks entries by category/slug", () => {
112
+ const tracker = new TokenTracker(1000);
113
+ const a = makeEntry({ category: "cat-a", slug: "one", content: contentOfTokens(100) });
114
+ const b = makeEntry({ category: "cat-b", slug: "one", content: contentOfTokens(100) });
115
+ tracker.reserve(a);
116
+ tracker.reserve(b);
117
+ expect(tracker.remaining).toBe(800);
118
+ });
119
+ });
120
+ describe("release", () => {
121
+ it("returns tokens to the budget", () => {
122
+ const tracker = new TokenTracker(1000);
123
+ const entry = makeEntry({ content: contentOfTokens(300) });
124
+ tracker.reserve(entry);
125
+ expect(tracker.remaining).toBe(700);
126
+ tracker.release(entry);
127
+ expect(tracker.remaining).toBe(1000);
128
+ });
129
+ it("is a no-op for entries not reserved", () => {
130
+ const tracker = new TokenTracker(1000);
131
+ const entry = makeEntry({ content: contentOfTokens(100) });
132
+ tracker.release(entry); // should not throw
133
+ expect(tracker.remaining).toBe(1000);
134
+ });
135
+ it("allows re-reserving after release", () => {
136
+ const tracker = new TokenTracker(1000);
137
+ const entry = makeEntry({ content: contentOfTokens(200) });
138
+ tracker.reserve(entry);
139
+ tracker.release(entry);
140
+ tracker.reserve(entry);
141
+ expect(tracker.remaining).toBe(800);
142
+ });
143
+ });
144
+ // ---------------------------------------------------------------------------
145
+ // selectEntries — highest_confidence
146
+ // ---------------------------------------------------------------------------
147
+ describe("selectEntries — highest_confidence", () => {
148
+ it("selects entries in descending confidence order", () => {
149
+ const tracker = new TokenTracker(1000);
150
+ const entries = [
151
+ { entry: makeEntry({ slug: "low", content: contentOfTokens(100) }), confidence: 0.3 },
152
+ { entry: makeEntry({ slug: "high", content: contentOfTokens(100) }), confidence: 0.9 },
153
+ { entry: makeEntry({ slug: "mid", content: contentOfTokens(100) }), confidence: 0.6 },
154
+ ];
155
+ const selected = tracker.selectEntries(entries, "highest_confidence");
156
+ expect(selected.map((e) => e.slug)).toEqual(["high", "mid", "low"]);
157
+ });
158
+ it("skips entries that do not fit", () => {
159
+ const tracker = new TokenTracker(250);
160
+ const entries = [
161
+ { entry: makeEntry({ slug: "a", content: contentOfTokens(100) }), confidence: 0.9 },
162
+ { entry: makeEntry({ slug: "b", content: contentOfTokens(200) }), confidence: 0.8 },
163
+ { entry: makeEntry({ slug: "c", content: contentOfTokens(100) }), confidence: 0.7 },
164
+ ];
165
+ const selected = tracker.selectEntries(entries, "highest_confidence");
166
+ // a (100) fits, b (200) doesn't (only 150 left), c (100) fits
167
+ expect(selected.map((e) => e.slug)).toEqual(["a", "c"]);
168
+ });
169
+ it("treats missing confidence as 0", () => {
170
+ const tracker = new TokenTracker(1000);
171
+ const entries = [
172
+ { entry: makeEntry({ slug: "no-score", content: contentOfTokens(50) }) },
173
+ { entry: makeEntry({ slug: "scored", content: contentOfTokens(50) }), confidence: 0.5 },
174
+ ];
175
+ const selected = tracker.selectEntries(entries, "highest_confidence");
176
+ expect(selected[0].slug).toBe("scored");
177
+ });
178
+ });
179
+ // ---------------------------------------------------------------------------
180
+ // selectEntries — most_relevant
181
+ // ---------------------------------------------------------------------------
182
+ describe("selectEntries — most_relevant", () => {
183
+ it("selects entries in descending relevance order", () => {
184
+ const tracker = new TokenTracker(1000);
185
+ const entries = [
186
+ { entry: makeEntry({ slug: "low", content: contentOfTokens(50) }), relevance: 0.2 },
187
+ { entry: makeEntry({ slug: "high", content: contentOfTokens(50) }), relevance: 0.95 },
188
+ { entry: makeEntry({ slug: "mid", content: contentOfTokens(50) }), relevance: 0.5 },
189
+ ];
190
+ const selected = tracker.selectEntries(entries, "most_relevant");
191
+ expect(selected.map((e) => e.slug)).toEqual(["high", "mid", "low"]);
192
+ });
193
+ it("falls back to array order when no relevance scores provided", () => {
194
+ const tracker = new TokenTracker(1000);
195
+ const entries = [
196
+ { entry: makeEntry({ slug: "first", content: contentOfTokens(50) }) },
197
+ { entry: makeEntry({ slug: "second", content: contentOfTokens(50) }) },
198
+ ];
199
+ const selected = tracker.selectEntries(entries, "most_relevant");
200
+ // Both have relevance 0, so sort is stable
201
+ expect(selected).toHaveLength(2);
202
+ });
203
+ });
204
+ // ---------------------------------------------------------------------------
205
+ // selectEntries — balanced
206
+ // ---------------------------------------------------------------------------
207
+ describe("selectEntries — balanced", () => {
208
+ it("interleaves entries from different categories", () => {
209
+ const tracker = new TokenTracker(1000);
210
+ const entries = [
211
+ { entry: makeEntry({ category: "science", slug: "s1", content: contentOfTokens(50) }), confidence: 0.9 },
212
+ { entry: makeEntry({ category: "science", slug: "s2", content: contentOfTokens(50) }), confidence: 0.8 },
213
+ { entry: makeEntry({ category: "history", slug: "h1", content: contentOfTokens(50) }), confidence: 0.85 },
214
+ { entry: makeEntry({ category: "history", slug: "h2", content: contentOfTokens(50) }), confidence: 0.7 },
215
+ ];
216
+ const selected = tracker.selectEntries(entries, "balanced");
217
+ // Should interleave: science first (higher top score), then history, then science, then history
218
+ expect(selected).toHaveLength(4);
219
+ // Check categories alternate
220
+ const categories = selected.map((e) => e.category);
221
+ expect(categories[0]).toBe("science");
222
+ expect(categories[1]).toBe("history");
223
+ expect(categories[2]).toBe("science");
224
+ expect(categories[3]).toBe("history");
225
+ });
226
+ it("respects budget when interleaving", () => {
227
+ const tracker = new TokenTracker(150);
228
+ const entries = [
229
+ { entry: makeEntry({ category: "a", slug: "a1", content: contentOfTokens(100) }), confidence: 0.9 },
230
+ { entry: makeEntry({ category: "b", slug: "b1", content: contentOfTokens(100) }), confidence: 0.8 },
231
+ ];
232
+ const selected = tracker.selectEntries(entries, "balanced");
233
+ // Only one fits
234
+ expect(selected).toHaveLength(1);
235
+ expect(selected[0].slug).toBe("a1");
236
+ });
237
+ it("uses combined confidence and relevance score", () => {
238
+ const tracker = new TokenTracker(1000);
239
+ const entries = [
240
+ {
241
+ entry: makeEntry({ category: "x", slug: "low-both", content: contentOfTokens(50) }),
242
+ confidence: 0.2,
243
+ relevance: 0.2,
244
+ },
245
+ {
246
+ entry: makeEntry({ category: "x", slug: "high-both", content: contentOfTokens(50) }),
247
+ confidence: 0.9,
248
+ relevance: 0.9,
249
+ },
250
+ ];
251
+ const selected = tracker.selectEntries(entries, "balanced");
252
+ expect(selected[0].slug).toBe("high-both");
253
+ });
254
+ });
255
+ // ---------------------------------------------------------------------------
256
+ // selectEntries — budget overflow prevention
257
+ // ---------------------------------------------------------------------------
258
+ describe("selectEntries — budget overflow prevention", () => {
259
+ it("never exceeds remaining budget", () => {
260
+ const tracker = new TokenTracker(100);
261
+ // Pre-reserve some tokens
262
+ const reserved = makeEntry({ slug: "reserved", content: contentOfTokens(60) });
263
+ tracker.reserve(reserved);
264
+ expect(tracker.remaining).toBe(40);
265
+ const entries = [
266
+ { entry: makeEntry({ slug: "big", content: contentOfTokens(50) }), confidence: 0.9 },
267
+ { entry: makeEntry({ slug: "small", content: contentOfTokens(30) }), confidence: 0.5 },
268
+ ];
269
+ const selected = tracker.selectEntries(entries, "highest_confidence");
270
+ // big (50) doesn't fit (only 40 left), small (30) fits
271
+ expect(selected).toHaveLength(1);
272
+ expect(selected[0].slug).toBe("small");
273
+ });
274
+ it("returns empty array when no entries fit", () => {
275
+ const tracker = new TokenTracker(10);
276
+ const entries = [
277
+ { entry: makeEntry({ slug: "a", content: contentOfTokens(50) }), confidence: 0.9 },
278
+ ];
279
+ const selected = tracker.selectEntries(entries, "highest_confidence");
280
+ expect(selected).toEqual([]);
281
+ });
282
+ it("does not mutate the tracker's remaining budget", () => {
283
+ const tracker = new TokenTracker(500);
284
+ const entries = [
285
+ { entry: makeEntry({ slug: "a", content: contentOfTokens(100) }), confidence: 0.9 },
286
+ ];
287
+ tracker.selectEntries(entries, "highest_confidence");
288
+ // selectEntries is read-only — does not actually reserve
289
+ expect(tracker.remaining).toBe(500);
290
+ });
291
+ });
292
+ //# sourceMappingURL=token-tracker.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token-tracker.test.js","sourceRoot":"","sources":["../../../src/budget/__tests__/token-tracker.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Budget Tracker — configurable spend limits with daily reset (UTC).
3
+ *
4
+ * Uses the shared cq_settings table for config storage and a dedicated
5
+ * research_budget table for charge records.
6
+ */
7
+ import type { BudgetConfig, BudgetCheckResult, BudgetStatus, ChargeType } from "./types.js";
8
+ export type { BudgetConfig, BudgetCheckResult, BudgetStatus, ChargeType } from "./types.js";
9
+ export { TokenTracker, estimateTokens } from "./token-tracker.js";
10
+ export type { SelectionStrategy, ScoredEntry } from "./token-tracker.js";
11
+ /** Ensure budget tables exist. Called lazily on first use. */
12
+ export declare function initBudgetTables(): void;
13
+ /**
14
+ * Store a BudgetConfig in the settings table.
15
+ * Merges with defaults so callers can provide partial overrides.
16
+ */
17
+ export declare function setBudgetConfig(config: Partial<BudgetConfig>): void;
18
+ /**
19
+ * Retrieve the stored BudgetConfig, falling back to defaults.
20
+ */
21
+ export declare function getBudgetConfig(): BudgetConfig;
22
+ /**
23
+ * Record a charge against the budget.
24
+ */
25
+ export declare function charge(type: ChargeType, costUsd: number, description?: string, now?: string): void;
26
+ /**
27
+ * Check whether an estimated charge fits within budget limits.
28
+ */
29
+ export declare function checkBudget(estimatedCost?: number, now?: string): BudgetCheckResult;
30
+ /**
31
+ * Return usage vs daily limit for a given date (defaults to today UTC).
32
+ */
33
+ export declare function getDailyBudgetStatus(now?: string): BudgetStatus;
34
+ /**
35
+ * Return lifetime usage vs total limit (if configured).
36
+ */
37
+ export declare function getTotalBudgetStatus(): BudgetStatus;
38
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/budget/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,iBAAiB,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE5F,YAAY,EAAE,YAAY,EAAE,iBAAiB,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC5F,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAClE,YAAY,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAyCzE,8DAA8D;AAC9D,wBAAgB,gBAAgB,IAAI,IAAI,CAKvC;AAsBD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,OAAO,CAAC,YAAY,CAAC,GAAG,IAAI,CAOnE;AAED;;GAEG;AACH,wBAAgB,eAAe,IAAI,YAAY,CAQ9C;AAMD;;GAEG;AACH,wBAAgB,MAAM,CAAC,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAQlG;AAMD;;GAEG;AACH,wBAAgB,WAAW,CAAC,aAAa,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,iBAAiB,CAmDnF;AAMD;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,YAAY,CAgB/D;AAED;;GAEG;AACH,wBAAgB,oBAAoB,IAAI,YAAY,CAiBnD"}
@@ -0,0 +1,192 @@
1
+ /**
2
+ * Budget Tracker — configurable spend limits with daily reset (UTC).
3
+ *
4
+ * Uses the shared cq_settings table for config storage and a dedicated
5
+ * research_budget table for charge records.
6
+ */
7
+ import { getDb } from "../metadata/index.js";
8
+ export { TokenTracker, estimateTokens } from "./token-tracker.js";
9
+ // ---------------------------------------------------------------------------
10
+ // Table DDL
11
+ // ---------------------------------------------------------------------------
12
+ const SETTINGS_TABLE_SQL = `
13
+ CREATE TABLE IF NOT EXISTS cq_settings (
14
+ key TEXT PRIMARY KEY,
15
+ value TEXT NOT NULL
16
+ );
17
+ `;
18
+ const BUDGET_TABLE_SQL = `
19
+ CREATE TABLE IF NOT EXISTS research_budget (
20
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
21
+ date TEXT NOT NULL,
22
+ type TEXT NOT NULL,
23
+ cost_usd REAL NOT NULL,
24
+ description TEXT,
25
+ created_at TEXT NOT NULL
26
+ );
27
+ `;
28
+ const CONFIG_KEY = "budget_config";
29
+ // ---------------------------------------------------------------------------
30
+ // Default config
31
+ // ---------------------------------------------------------------------------
32
+ const DEFAULT_CONFIG = {
33
+ dailyLimitUsd: 1.0,
34
+ searchCostUsd: 0.03,
35
+ synthesisCostUsd: 0.01,
36
+ vetCostUsd: 0.005,
37
+ };
38
+ // ---------------------------------------------------------------------------
39
+ // Initialisation
40
+ // ---------------------------------------------------------------------------
41
+ /** Ensure budget tables exist. Called lazily on first use. */
42
+ export function initBudgetTables() {
43
+ const db = getDb();
44
+ if (!db)
45
+ throw new Error("Metadata DB not initialised — call initMetadataDb first");
46
+ db.exec(SETTINGS_TABLE_SQL);
47
+ db.exec(BUDGET_TABLE_SQL);
48
+ }
49
+ // ---------------------------------------------------------------------------
50
+ // Helpers
51
+ // ---------------------------------------------------------------------------
52
+ /** Return today's date as YYYY-MM-DD in UTC. */
53
+ function utcToday(now) {
54
+ const d = now ? new Date(now) : new Date();
55
+ return d.toISOString().slice(0, 10);
56
+ }
57
+ function requireDb() {
58
+ const db = getDb();
59
+ if (!db)
60
+ throw new Error("Metadata DB not initialised — call initMetadataDb first");
61
+ return db;
62
+ }
63
+ // ---------------------------------------------------------------------------
64
+ // Config storage
65
+ // ---------------------------------------------------------------------------
66
+ /**
67
+ * Store a BudgetConfig in the settings table.
68
+ * Merges with defaults so callers can provide partial overrides.
69
+ */
70
+ export function setBudgetConfig(config) {
71
+ initBudgetTables();
72
+ const db = requireDb();
73
+ const merged = { ...DEFAULT_CONFIG, ...config };
74
+ db.prepare("INSERT INTO cq_settings (key, value) VALUES (?, ?) ON CONFLICT (key) DO UPDATE SET value = ?").run(CONFIG_KEY, JSON.stringify(merged), JSON.stringify(merged));
75
+ }
76
+ /**
77
+ * Retrieve the stored BudgetConfig, falling back to defaults.
78
+ */
79
+ export function getBudgetConfig() {
80
+ initBudgetTables();
81
+ const db = requireDb();
82
+ const row = db.prepare("SELECT value FROM cq_settings WHERE key = ?").get(CONFIG_KEY);
83
+ if (!row)
84
+ return { ...DEFAULT_CONFIG };
85
+ return JSON.parse(row.value);
86
+ }
87
+ // ---------------------------------------------------------------------------
88
+ // Charging
89
+ // ---------------------------------------------------------------------------
90
+ /**
91
+ * Record a charge against the budget.
92
+ */
93
+ export function charge(type, costUsd, description, now) {
94
+ initBudgetTables();
95
+ const db = requireDb();
96
+ const date = utcToday(now);
97
+ const createdAt = now ?? new Date().toISOString();
98
+ db.prepare("INSERT INTO research_budget (date, type, cost_usd, description, created_at) VALUES (?, ?, ?, ?, ?)").run(date, type, costUsd, description ?? null, createdAt);
99
+ }
100
+ // ---------------------------------------------------------------------------
101
+ // Budget checks
102
+ // ---------------------------------------------------------------------------
103
+ /**
104
+ * Check whether an estimated charge fits within budget limits.
105
+ */
106
+ export function checkBudget(estimatedCost, now) {
107
+ initBudgetTables();
108
+ const db = requireDb();
109
+ const config = getBudgetConfig();
110
+ const date = utcToday(now);
111
+ const cost = estimatedCost ?? 0;
112
+ const dailyRow = db
113
+ .prepare("SELECT COALESCE(SUM(cost_usd), 0) AS total FROM research_budget WHERE date = ?")
114
+ .get(date);
115
+ const dailyUsedUsd = dailyRow.total;
116
+ const totalRow = db
117
+ .prepare("SELECT COALESCE(SUM(cost_usd), 0) AS total FROM research_budget")
118
+ .get();
119
+ const totalUsedUsd = totalRow.total;
120
+ const dailyRemaining = config.dailyLimitUsd - dailyUsedUsd;
121
+ const totalRemaining = config.totalLimitUsd !== undefined
122
+ ? config.totalLimitUsd - totalUsedUsd
123
+ : Infinity;
124
+ const remainingUsd = Math.min(dailyRemaining, totalRemaining);
125
+ // Check daily limit
126
+ if (dailyUsedUsd + cost > config.dailyLimitUsd) {
127
+ return {
128
+ allowed: false,
129
+ remainingUsd: Math.max(0, dailyRemaining),
130
+ dailyUsedUsd,
131
+ totalUsedUsd,
132
+ reason: `Daily limit of $${config.dailyLimitUsd.toFixed(2)} would be exceeded (used: $${dailyUsedUsd.toFixed(2)}, requested: $${cost.toFixed(2)})`,
133
+ };
134
+ }
135
+ // Check total limit
136
+ if (config.totalLimitUsd !== undefined && totalUsedUsd + cost > config.totalLimitUsd) {
137
+ return {
138
+ allowed: false,
139
+ remainingUsd: Math.max(0, totalRemaining),
140
+ dailyUsedUsd,
141
+ totalUsedUsd,
142
+ reason: `Total limit of $${config.totalLimitUsd.toFixed(2)} would be exceeded (used: $${totalUsedUsd.toFixed(2)}, requested: $${cost.toFixed(2)})`,
143
+ };
144
+ }
145
+ return {
146
+ allowed: true,
147
+ remainingUsd: Math.max(0, remainingUsd),
148
+ dailyUsedUsd,
149
+ totalUsedUsd,
150
+ };
151
+ }
152
+ // ---------------------------------------------------------------------------
153
+ // Status queries
154
+ // ---------------------------------------------------------------------------
155
+ /**
156
+ * Return usage vs daily limit for a given date (defaults to today UTC).
157
+ */
158
+ export function getDailyBudgetStatus(now) {
159
+ initBudgetTables();
160
+ const db = requireDb();
161
+ const config = getBudgetConfig();
162
+ const date = utcToday(now);
163
+ const row = db
164
+ .prepare("SELECT COALESCE(SUM(cost_usd), 0) AS total FROM research_budget WHERE date = ?")
165
+ .get(date);
166
+ const usedUsd = row.total;
167
+ return {
168
+ usedUsd,
169
+ limitUsd: config.dailyLimitUsd,
170
+ remainingUsd: Math.max(0, config.dailyLimitUsd - usedUsd),
171
+ };
172
+ }
173
+ /**
174
+ * Return lifetime usage vs total limit (if configured).
175
+ */
176
+ export function getTotalBudgetStatus() {
177
+ initBudgetTables();
178
+ const db = requireDb();
179
+ const config = getBudgetConfig();
180
+ const row = db
181
+ .prepare("SELECT COALESCE(SUM(cost_usd), 0) AS total FROM research_budget")
182
+ .get();
183
+ const usedUsd = row.total;
184
+ return {
185
+ usedUsd,
186
+ limitUsd: config.totalLimitUsd,
187
+ remainingUsd: config.totalLimitUsd !== undefined
188
+ ? Math.max(0, config.totalLimitUsd - usedUsd)
189
+ : undefined,
190
+ };
191
+ }
192
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/budget/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Token Tracker — runtime context window budget management.
3
+ *
4
+ * Tracks token usage for knowledge entries loaded into an LLM context window.
5
+ * Supports multiple selection strategies for fitting entries within a budget.
6
+ */
7
+ import type { KnowledgeEntry } from "../knowledge-tree/types.js";
8
+ /** Strategy for selecting entries that fit within the token budget. */
9
+ export type SelectionStrategy = "highest_confidence" | "most_relevant" | "balanced";
10
+ /** An entry paired with optional scoring metadata for selection. */
11
+ export interface ScoredEntry {
12
+ entry: KnowledgeEntry;
13
+ /** Confidence score (0–1). Used by highest_confidence and balanced strategies. */
14
+ confidence?: number;
15
+ /** Relevance score (0–1). Used by most_relevant strategy. */
16
+ relevance?: number;
17
+ }
18
+ /** Estimate token count from content length (~4 chars per token). */
19
+ export declare function estimateTokens(content: string): number;
20
+ /**
21
+ * Manages a token budget for loading knowledge entries into a context window.
22
+ *
23
+ * Not backed by SQLite — this is a purely in-memory runtime tracker.
24
+ */
25
+ export declare class TokenTracker {
26
+ private readonly maxTokens;
27
+ private used;
28
+ private reserved;
29
+ constructor(maxTokens: number);
30
+ /** Key for deduplication in the reserved map. */
31
+ private entryKey;
32
+ /** Current available tokens. */
33
+ get remaining(): number;
34
+ /** Check whether an entry's content fits in the remaining budget. */
35
+ wouldFit(entry: KnowledgeEntry): boolean;
36
+ /**
37
+ * Reserve tokens for an entry, deducting from the remaining budget.
38
+ * Throws if the entry would exceed the budget.
39
+ * No-op if the entry is already reserved.
40
+ */
41
+ reserve(entry: KnowledgeEntry): void;
42
+ /**
43
+ * Release tokens previously reserved for an entry, returning them to the budget.
44
+ * No-op if the entry is not currently reserved.
45
+ */
46
+ release(entry: KnowledgeEntry): void;
47
+ /**
48
+ * Select entries that fit within the remaining budget using the given strategy.
49
+ *
50
+ * @param entries - Scored entries to consider.
51
+ * @param strategy - Selection strategy.
52
+ * @returns Entries selected to fit within budget, ordered by strategy priority.
53
+ */
54
+ selectEntries(entries: ScoredEntry[], strategy: SelectionStrategy): KnowledgeEntry[];
55
+ private sortByStrategy;
56
+ /**
57
+ * Balanced strategy: interleave entries from different categories,
58
+ * sorted within each category by a combined confidence + relevance score.
59
+ */
60
+ private balancedSort;
61
+ }
62
+ //# sourceMappingURL=token-tracker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token-tracker.d.ts","sourceRoot":"","sources":["../../src/budget/token-tracker.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAMjE,uEAAuE;AACvE,MAAM,MAAM,iBAAiB,GAAG,oBAAoB,GAAG,eAAe,GAAG,UAAU,CAAC;AAEpF,oEAAoE;AACpE,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,cAAc,CAAC;IACtB,kFAAkF;IAClF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,6DAA6D;IAC7D,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAMD,qEAAqE;AACrE,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEtD;AAMD;;;;GAIG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,IAAI,CAAa;IACzB,OAAO,CAAC,QAAQ,CAAkC;gBAEtC,SAAS,EAAE,MAAM;IAO7B,iDAAiD;IACjD,OAAO,CAAC,QAAQ;IAIhB,gCAAgC;IAChC,IAAI,SAAS,IAAI,MAAM,CAEtB;IAED,qEAAqE;IACrE,QAAQ,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO;IAKxC;;;;OAIG;IACH,OAAO,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI;IAcpC;;;OAGG;IACH,OAAO,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI;IASpC;;;;;;OAMG;IACH,aAAa,CAAC,OAAO,EAAE,WAAW,EAAE,EAAE,QAAQ,EAAE,iBAAiB,GAAG,cAAc,EAAE;IAoBpF,OAAO,CAAC,cAAc;IAatB;;;OAGG;IACH,OAAO,CAAC,YAAY;CA8CrB"}