@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,8 @@
1
+ /**
2
+ * Integration test for initCQ — the unified CQ public API.
3
+ *
4
+ * Tests: initCQ > addCuriosity > runOrchestrator > verify knowledge entry created.
5
+ * Uses mock providers to avoid real API calls.
6
+ */
7
+ export {};
8
+ //# sourceMappingURL=integration.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"integration.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/integration.test.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
@@ -0,0 +1,233 @@
1
+ /**
2
+ * Integration test for initCQ — the unified CQ public API.
3
+ *
4
+ * Tests: initCQ > addCuriosity > runOrchestrator > verify knowledge entry created.
5
+ * Uses mock providers to avoid real API calls.
6
+ */
7
+ import { describe, it, expect, afterEach } from "vitest";
8
+ import { mkdtemp, rm } from "node:fs/promises";
9
+ import { join } from "node:path";
10
+ import { tmpdir } from "node:os";
11
+ import { initCQ } from "../init.js";
12
+ // ---------------------------------------------------------------------------
13
+ // Mock providers
14
+ // ---------------------------------------------------------------------------
15
+ class MockSearchProvider {
16
+ name = "mock-search";
17
+ _lastCost = 0;
18
+ callCount = 0;
19
+ async search(query) {
20
+ this.callCount++;
21
+ this._lastCost = 0.01;
22
+ return [
23
+ {
24
+ title: `Search result for: ${query}`,
25
+ url: "https://example.com/mock-result",
26
+ snippet: "A detailed and informative snippet about the topic with plenty of content.",
27
+ content: "Comprehensive mock content about the topic with sufficient detail and length " +
28
+ "to pass all vetting checks. This includes multiple paragraphs of information " +
29
+ "that cover the subject thoroughly.\n\n" +
30
+ "## Key Points\n\n" +
31
+ "- Point one with detail\n" +
32
+ "- Point two with detail\n" +
33
+ "- Point three with detail\n\n" +
34
+ "The topic is well-researched and documented across multiple authoritative sources.",
35
+ },
36
+ ];
37
+ }
38
+ lastCallCostUsd() {
39
+ return this._lastCost;
40
+ }
41
+ }
42
+ class MockModelProvider {
43
+ name = "mock-model";
44
+ _lastCost = 0;
45
+ callCount = 0;
46
+ async synthesize(question, searchResults) {
47
+ this.callCount++;
48
+ this._lastCost = 0.005;
49
+ return {
50
+ title: `Knowledge: ${question.slice(0, 40)}`,
51
+ category: "technology",
52
+ content: `Synthesised answer about "${question}" from ${searchResults.length} source(s). This contains enough detail to be useful.`,
53
+ tags: ["research", "mock"],
54
+ source: searchResults[0]?.url ?? "unknown",
55
+ confidence: 0.85,
56
+ };
57
+ }
58
+ async categorize(_content, categories) {
59
+ this._lastCost = 0.001;
60
+ return categories[0] ?? "technology";
61
+ }
62
+ lastCallCostUsd() {
63
+ return this._lastCost;
64
+ }
65
+ }
66
+ // ---------------------------------------------------------------------------
67
+ // Tests
68
+ // ---------------------------------------------------------------------------
69
+ describe("initCQ integration", () => {
70
+ let tmpDir;
71
+ let cq;
72
+ afterEach(async () => {
73
+ if (cq) {
74
+ cq.close();
75
+ }
76
+ if (tmpDir) {
77
+ await rm(tmpDir, { recursive: true, force: true });
78
+ }
79
+ });
80
+ it("initialises all subsystems from a single config", async () => {
81
+ tmpDir = await mkdtemp(join(tmpdir(), "cq-integration-"));
82
+ cq = await initCQ({
83
+ dataDir: tmpDir,
84
+ budget: { dailyLimitUsd: 5.0 },
85
+ confidence: { default_rate: 0.01 },
86
+ providers: {
87
+ search: new MockSearchProvider(),
88
+ model: new MockModelProvider(),
89
+ },
90
+ });
91
+ // Verify all subsystem namespaces exist
92
+ expect(cq.knowledge).toBeDefined();
93
+ expect(cq.metadata).toBeDefined();
94
+ expect(cq.confidence).toBeDefined();
95
+ expect(cq.curiosity).toBeDefined();
96
+ expect(cq.pipeline).toBeDefined();
97
+ expect(cq.vetter).toBeDefined();
98
+ expect(cq.budget).toBeDefined();
99
+ expect(cq.tokenTracker).toBeDefined();
100
+ expect(cq.orchestrator).toBeDefined();
101
+ expect(cq.scheduler).toBeDefined();
102
+ expect(cq.db).toBeDefined();
103
+ expect(cq.dataDir).toBe(tmpDir);
104
+ expect(cq.close).toBeInstanceOf(Function);
105
+ // Verify config was applied
106
+ const budgetConfig = cq.budget.getBudgetConfig();
107
+ expect(budgetConfig.dailyLimitUsd).toBe(5.0);
108
+ const confidenceConfig = cq.confidence.getConfidenceConfig();
109
+ expect(confidenceConfig.default_rate).toBe(0.01);
110
+ });
111
+ it("full flow: addCuriosity > runOrchestrator > knowledge entry created", async () => {
112
+ tmpDir = await mkdtemp(join(tmpdir(), "cq-integration-"));
113
+ const mockSearch = new MockSearchProvider();
114
+ const mockModel = new MockModelProvider();
115
+ cq = await initCQ({
116
+ dataDir: tmpDir,
117
+ budget: { dailyLimitUsd: 10.0 },
118
+ providers: {
119
+ search: mockSearch,
120
+ model: mockModel,
121
+ },
122
+ });
123
+ // 1. Add a curiosity item
124
+ const item = cq.curiosity.addCuriosity({
125
+ question: "What is quantum computing?",
126
+ context: "Integration test question",
127
+ source: "agent",
128
+ priority: 8,
129
+ });
130
+ expect(item).not.toBeNull();
131
+ expect(item.id).toBeGreaterThan(0);
132
+ // Verify it's in the queue
133
+ const pending = cq.curiosity.fetchPending(10);
134
+ expect(pending.length).toBe(1);
135
+ expect(pending[0].question).toBe("What is quantum computing?");
136
+ // 2. Run the orchestrator
137
+ const result = await cq.orchestrator.runOrchestrator({
138
+ db: cq.db,
139
+ dataDir: cq.dataDir,
140
+ searchProvider: cq.searchProvider,
141
+ modelProvider: cq.modelProvider,
142
+ maxCuriosityItems: 5,
143
+ });
144
+ expect(result.status).toBe("completed");
145
+ expect(result.phases.curiosity.processed).toBeGreaterThanOrEqual(1);
146
+ expect(result.phases.curiosity.succeeded).toBeGreaterThanOrEqual(1);
147
+ // 3. Verify that mock providers were called
148
+ expect(mockSearch.callCount).toBeGreaterThanOrEqual(1);
149
+ expect(mockModel.callCount).toBeGreaterThanOrEqual(1);
150
+ // 4. Verify a knowledge entry was created on disk
151
+ const categories = await cq.knowledge.listCategories(tmpDir);
152
+ expect(categories.length).toBeGreaterThanOrEqual(1);
153
+ // Find entries in the created category
154
+ const allEntries = [];
155
+ for (const cat of categories) {
156
+ const entries = await cq.knowledge.listEntries(tmpDir, cat.name);
157
+ for (const entry of entries) {
158
+ allEntries.push(`${entry.category}/${entry.slug}`);
159
+ }
160
+ }
161
+ expect(allEntries.length).toBeGreaterThanOrEqual(1);
162
+ // 5. Verify the curiosity item was completed
163
+ const completedItem = cq.curiosity.getItem(item.id);
164
+ expect(completedItem).not.toBeNull();
165
+ expect(completedItem.status).toBe("completed");
166
+ // 6. Verify orchestrator run was logged
167
+ const runs = cq.orchestrator.getRecentRuns(cq.db, 5);
168
+ expect(runs.length).toBeGreaterThanOrEqual(1);
169
+ expect(runs[0].status).toBe("completed");
170
+ });
171
+ it("close() shuts down database and scheduler", async () => {
172
+ tmpDir = await mkdtemp(join(tmpdir(), "cq-integration-"));
173
+ cq = await initCQ({
174
+ dataDir: tmpDir,
175
+ providers: {
176
+ search: new MockSearchProvider(),
177
+ model: new MockModelProvider(),
178
+ },
179
+ });
180
+ // DB should be open
181
+ expect(cq.db.open).toBe(true);
182
+ // Close
183
+ cq.close();
184
+ // DB should be closed
185
+ expect(cq.db.open).toBe(false);
186
+ });
187
+ it("scheduler starts and stops via config", async () => {
188
+ tmpDir = await mkdtemp(join(tmpdir(), "cq-integration-"));
189
+ cq = await initCQ({
190
+ dataDir: tmpDir,
191
+ providers: {
192
+ search: new MockSearchProvider(),
193
+ model: new MockModelProvider(),
194
+ },
195
+ scheduler: {
196
+ cron: "0 3 *",
197
+ },
198
+ });
199
+ // Scheduler should be running
200
+ expect(cq.scheduler.isSchedulerRunning()).toBe(true);
201
+ // close() should stop it
202
+ cq.close();
203
+ expect(cq.scheduler.isSchedulerRunning()).toBe(false);
204
+ });
205
+ it("curiosity queue dedup works through the unified API", async () => {
206
+ tmpDir = await mkdtemp(join(tmpdir(), "cq-integration-"));
207
+ cq = await initCQ({
208
+ dataDir: tmpDir,
209
+ providers: {
210
+ search: new MockSearchProvider(),
211
+ model: new MockModelProvider(),
212
+ },
213
+ });
214
+ const item1 = cq.curiosity.addCuriosity({
215
+ question: "What is machine learning?",
216
+ context: "",
217
+ source: "agent",
218
+ priority: 5,
219
+ });
220
+ expect(item1).not.toBeNull();
221
+ // Same question should be deduped
222
+ const item2 = cq.curiosity.addCuriosity({
223
+ question: "What is machine learning?",
224
+ context: "",
225
+ source: "agent",
226
+ priority: 5,
227
+ });
228
+ expect(item2).toBeNull();
229
+ const counts = cq.curiosity.countByStatus();
230
+ expect(counts.pending).toBe(1);
231
+ });
232
+ });
233
+ //# sourceMappingURL=integration.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"integration.test.js","sourceRoot":"","sources":["../../src/__tests__/integration.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=budget.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"budget.test.d.ts","sourceRoot":"","sources":["../../../src/budget/__tests__/budget.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,238 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from "vitest";
2
+ import { initMetadataDb, closeDb } from "../../metadata/index.js";
3
+ import { setBudgetConfig, getBudgetConfig, charge, checkBudget, getDailyBudgetStatus, getTotalBudgetStatus, initBudgetTables, } from "../index.js";
4
+ // ---------------------------------------------------------------------------
5
+ // Setup / teardown
6
+ // ---------------------------------------------------------------------------
7
+ beforeEach(() => {
8
+ initMetadataDb(":memory:");
9
+ });
10
+ afterEach(() => {
11
+ closeDb();
12
+ });
13
+ // ---------------------------------------------------------------------------
14
+ // Config storage
15
+ // ---------------------------------------------------------------------------
16
+ describe("setBudgetConfig / getBudgetConfig", () => {
17
+ it("returns defaults when no config has been set", () => {
18
+ const config = getBudgetConfig();
19
+ expect(config.dailyLimitUsd).toBe(1.0);
20
+ expect(config.searchCostUsd).toBe(0.03);
21
+ expect(config.synthesisCostUsd).toBe(0.01);
22
+ expect(config.vetCostUsd).toBe(0.005);
23
+ expect(config.totalLimitUsd).toBeUndefined();
24
+ });
25
+ it("stores and retrieves a custom config", () => {
26
+ const custom = {
27
+ dailyLimitUsd: 5.0,
28
+ totalLimitUsd: 50.0,
29
+ searchCostUsd: 0.05,
30
+ synthesisCostUsd: 0.02,
31
+ vetCostUsd: 0.01,
32
+ };
33
+ setBudgetConfig(custom);
34
+ const config = getBudgetConfig();
35
+ expect(config.dailyLimitUsd).toBe(5.0);
36
+ expect(config.totalLimitUsd).toBe(50.0);
37
+ expect(config.searchCostUsd).toBe(0.05);
38
+ expect(config.synthesisCostUsd).toBe(0.02);
39
+ expect(config.vetCostUsd).toBe(0.01);
40
+ });
41
+ it("overwrites previous config on re-set", () => {
42
+ setBudgetConfig({ dailyLimitUsd: 2.0 });
43
+ setBudgetConfig({ dailyLimitUsd: 10.0 });
44
+ expect(getBudgetConfig().dailyLimitUsd).toBe(10.0);
45
+ });
46
+ it("merges partial config with defaults", () => {
47
+ setBudgetConfig({ dailyLimitUsd: 3.0 });
48
+ const config = getBudgetConfig();
49
+ expect(config.dailyLimitUsd).toBe(3.0);
50
+ expect(config.searchCostUsd).toBe(0.03); // default preserved
51
+ });
52
+ });
53
+ // ---------------------------------------------------------------------------
54
+ // initBudgetTables
55
+ // ---------------------------------------------------------------------------
56
+ describe("initBudgetTables", () => {
57
+ it("throws if db not initialised", () => {
58
+ closeDb();
59
+ expect(() => initBudgetTables()).toThrow("Metadata DB not initialised");
60
+ });
61
+ it("is idempotent", () => {
62
+ initBudgetTables();
63
+ initBudgetTables(); // second call should not throw
64
+ });
65
+ });
66
+ // ---------------------------------------------------------------------------
67
+ // charge
68
+ // ---------------------------------------------------------------------------
69
+ describe("charge", () => {
70
+ it("records a charge that shows up in daily status", () => {
71
+ setBudgetConfig({ dailyLimitUsd: 1.0 });
72
+ const now = "2025-07-15T10:00:00.000Z";
73
+ charge("search", 0.03, "web search for AI agents", now);
74
+ const status = getDailyBudgetStatus(now);
75
+ expect(status.usedUsd).toBeCloseTo(0.03, 10);
76
+ });
77
+ it("records multiple charges", () => {
78
+ setBudgetConfig({ dailyLimitUsd: 1.0 });
79
+ const now = "2025-07-15T10:00:00.000Z";
80
+ charge("search", 0.03, undefined, now);
81
+ charge("synthesis", 0.01, undefined, now);
82
+ charge("vetting", 0.005, undefined, now);
83
+ const status = getDailyBudgetStatus(now);
84
+ expect(status.usedUsd).toBeCloseTo(0.045, 10);
85
+ });
86
+ it("accepts charges without description", () => {
87
+ const now = "2025-07-15T10:00:00.000Z";
88
+ charge("other", 0.10, undefined, now);
89
+ const status = getDailyBudgetStatus(now);
90
+ expect(status.usedUsd).toBeCloseTo(0.10, 10);
91
+ });
92
+ });
93
+ // ---------------------------------------------------------------------------
94
+ // checkBudget
95
+ // ---------------------------------------------------------------------------
96
+ describe("checkBudget", () => {
97
+ it("allows charge within daily limit", () => {
98
+ setBudgetConfig({ dailyLimitUsd: 1.0 });
99
+ const now = "2025-07-15T10:00:00.000Z";
100
+ const result = checkBudget(0.03, now);
101
+ expect(result.allowed).toBe(true);
102
+ expect(result.remainingUsd).toBeCloseTo(1.0, 10);
103
+ expect(result.dailyUsedUsd).toBe(0);
104
+ expect(result.totalUsedUsd).toBe(0);
105
+ });
106
+ it("denies charge exceeding daily limit", () => {
107
+ setBudgetConfig({ dailyLimitUsd: 0.05 });
108
+ const now = "2025-07-15T10:00:00.000Z";
109
+ charge("search", 0.04, undefined, now);
110
+ const result = checkBudget(0.03, now);
111
+ expect(result.allowed).toBe(false);
112
+ expect(result.reason).toContain("Daily limit");
113
+ expect(result.dailyUsedUsd).toBeCloseTo(0.04, 10);
114
+ });
115
+ it("denies charge exceeding total limit", () => {
116
+ setBudgetConfig({ dailyLimitUsd: 10.0, totalLimitUsd: 0.10 });
117
+ const day1 = "2025-07-14T10:00:00.000Z";
118
+ const day2 = "2025-07-15T10:00:00.000Z";
119
+ charge("search", 0.08, undefined, day1);
120
+ const result = checkBudget(0.05, day2);
121
+ expect(result.allowed).toBe(false);
122
+ expect(result.reason).toContain("Total limit");
123
+ expect(result.totalUsedUsd).toBeCloseTo(0.08, 10);
124
+ });
125
+ it("allows charge when no estimatedCost provided", () => {
126
+ setBudgetConfig({ dailyLimitUsd: 1.0 });
127
+ const now = "2025-07-15T10:00:00.000Z";
128
+ const result = checkBudget(undefined, now);
129
+ expect(result.allowed).toBe(true);
130
+ });
131
+ it("returns remaining budget correctly after charges", () => {
132
+ setBudgetConfig({ dailyLimitUsd: 1.0, totalLimitUsd: 5.0 });
133
+ const now = "2025-07-15T10:00:00.000Z";
134
+ charge("search", 0.30, undefined, now);
135
+ const result = checkBudget(0, now);
136
+ expect(result.allowed).toBe(true);
137
+ expect(result.remainingUsd).toBeCloseTo(0.70, 10);
138
+ expect(result.dailyUsedUsd).toBeCloseTo(0.30, 10);
139
+ expect(result.totalUsedUsd).toBeCloseTo(0.30, 10);
140
+ });
141
+ it("respects daily limit as the binding constraint", () => {
142
+ setBudgetConfig({ dailyLimitUsd: 0.50, totalLimitUsd: 100.0 });
143
+ const now = "2025-07-15T10:00:00.000Z";
144
+ charge("search", 0.45, undefined, now);
145
+ const result = checkBudget(0.10, now);
146
+ expect(result.allowed).toBe(false);
147
+ expect(result.reason).toContain("Daily limit");
148
+ });
149
+ });
150
+ // ---------------------------------------------------------------------------
151
+ // Daily reset (implicit via date filtering)
152
+ // ---------------------------------------------------------------------------
153
+ describe("daily reset", () => {
154
+ it("charges on different days do not affect each other's daily budget", () => {
155
+ setBudgetConfig({ dailyLimitUsd: 0.10 });
156
+ const day1 = "2025-07-15T23:59:00.000Z";
157
+ const day2 = "2025-07-16T00:01:00.000Z";
158
+ charge("search", 0.09, undefined, day1);
159
+ // Day 1 is nearly full
160
+ const status1 = getDailyBudgetStatus(day1);
161
+ expect(status1.usedUsd).toBeCloseTo(0.09, 10);
162
+ expect(status1.remainingUsd).toBeCloseTo(0.01, 10);
163
+ // Day 2 resets
164
+ const status2 = getDailyBudgetStatus(day2);
165
+ expect(status2.usedUsd).toBe(0);
166
+ expect(status2.remainingUsd).toBeCloseTo(0.10, 10);
167
+ });
168
+ it("checkBudget allows on new day after previous day was exhausted", () => {
169
+ setBudgetConfig({ dailyLimitUsd: 0.05 });
170
+ const day1 = "2025-07-15T10:00:00.000Z";
171
+ const day2 = "2025-07-16T10:00:00.000Z";
172
+ charge("search", 0.05, undefined, day1);
173
+ const check1 = checkBudget(0.01, day1);
174
+ expect(check1.allowed).toBe(false);
175
+ const check2 = checkBudget(0.01, day2);
176
+ expect(check2.allowed).toBe(true);
177
+ });
178
+ it("total limit still accumulates across days", () => {
179
+ setBudgetConfig({ dailyLimitUsd: 1.0, totalLimitUsd: 0.10 });
180
+ const day1 = "2025-07-15T10:00:00.000Z";
181
+ const day2 = "2025-07-16T10:00:00.000Z";
182
+ charge("search", 0.06, undefined, day1);
183
+ charge("search", 0.03, undefined, day2);
184
+ const totalStatus = getTotalBudgetStatus();
185
+ expect(totalStatus.usedUsd).toBeCloseTo(0.09, 10);
186
+ expect(totalStatus.remainingUsd).toBeCloseTo(0.01, 10);
187
+ });
188
+ });
189
+ // ---------------------------------------------------------------------------
190
+ // getDailyBudgetStatus
191
+ // ---------------------------------------------------------------------------
192
+ describe("getDailyBudgetStatus", () => {
193
+ it("returns zero usage when no charges exist", () => {
194
+ setBudgetConfig({ dailyLimitUsd: 2.0 });
195
+ const status = getDailyBudgetStatus("2025-07-15T10:00:00.000Z");
196
+ expect(status.usedUsd).toBe(0);
197
+ expect(status.limitUsd).toBe(2.0);
198
+ expect(status.remainingUsd).toBe(2.0);
199
+ });
200
+ it("reflects charges for the given date", () => {
201
+ setBudgetConfig({ dailyLimitUsd: 1.0 });
202
+ const now = "2025-07-15T10:00:00.000Z";
203
+ charge("search", 0.03, undefined, now);
204
+ charge("synthesis", 0.01, undefined, now);
205
+ const status = getDailyBudgetStatus(now);
206
+ expect(status.usedUsd).toBeCloseTo(0.04, 10);
207
+ expect(status.remainingUsd).toBeCloseTo(0.96, 10);
208
+ });
209
+ });
210
+ // ---------------------------------------------------------------------------
211
+ // getTotalBudgetStatus
212
+ // ---------------------------------------------------------------------------
213
+ describe("getTotalBudgetStatus", () => {
214
+ it("returns zero usage when no charges exist", () => {
215
+ const status = getTotalBudgetStatus();
216
+ expect(status.usedUsd).toBe(0);
217
+ expect(status.limitUsd).toBeUndefined();
218
+ expect(status.remainingUsd).toBeUndefined();
219
+ });
220
+ it("reports total limit and remaining when configured", () => {
221
+ setBudgetConfig({ dailyLimitUsd: 1.0, totalLimitUsd: 10.0 });
222
+ charge("search", 3.0, undefined, "2025-07-10T10:00:00.000Z");
223
+ charge("search", 2.0, undefined, "2025-07-11T10:00:00.000Z");
224
+ const status = getTotalBudgetStatus();
225
+ expect(status.usedUsd).toBeCloseTo(5.0, 10);
226
+ expect(status.limitUsd).toBe(10.0);
227
+ expect(status.remainingUsd).toBeCloseTo(5.0, 10);
228
+ });
229
+ it("returns undefined remaining when no total limit set", () => {
230
+ setBudgetConfig({ dailyLimitUsd: 1.0 });
231
+ charge("other", 0.50, undefined, "2025-07-15T10:00:00.000Z");
232
+ const status = getTotalBudgetStatus();
233
+ expect(status.usedUsd).toBeCloseTo(0.50, 10);
234
+ expect(status.limitUsd).toBeUndefined();
235
+ expect(status.remainingUsd).toBeUndefined();
236
+ });
237
+ });
238
+ //# sourceMappingURL=budget.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"budget.test.js","sourceRoot":"","sources":["../../../src/budget/__tests__/budget.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=token-tracker.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token-tracker.test.d.ts","sourceRoot":"","sources":["../../../src/budget/__tests__/token-tracker.test.ts"],"names":[],"mappings":""}