@matthias-hausberger/beige 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 (194) hide show
  1. package/LICENSE.md +8 -0
  2. package/README.md +183 -0
  3. package/dist/channels/registry.d.ts +14 -0
  4. package/dist/channels/registry.d.ts.map +1 -0
  5. package/dist/channels/registry.js +14 -0
  6. package/dist/channels/registry.js.map +1 -0
  7. package/dist/channels/telegram.d.ts +92 -0
  8. package/dist/channels/telegram.d.ts.map +1 -0
  9. package/dist/channels/telegram.js +469 -0
  10. package/dist/channels/telegram.js.map +1 -0
  11. package/dist/channels/tui.d.ts +8 -0
  12. package/dist/channels/tui.d.ts.map +1 -0
  13. package/dist/channels/tui.js +574 -0
  14. package/dist/channels/tui.js.map +1 -0
  15. package/dist/cli.d.ts +23 -0
  16. package/dist/cli.d.ts.map +1 -0
  17. package/dist/cli.js +571 -0
  18. package/dist/cli.js.map +1 -0
  19. package/dist/config/loader.d.ts +6 -0
  20. package/dist/config/loader.d.ts.map +1 -0
  21. package/dist/config/loader.js +103 -0
  22. package/dist/config/loader.js.map +1 -0
  23. package/dist/config/loader.spec.d.ts +2 -0
  24. package/dist/config/loader.spec.d.ts.map +1 -0
  25. package/dist/config/loader.spec.js +195 -0
  26. package/dist/config/loader.spec.js.map +1 -0
  27. package/dist/config/schema.d.ts +107 -0
  28. package/dist/config/schema.d.ts.map +1 -0
  29. package/dist/config/schema.js +42 -0
  30. package/dist/config/schema.js.map +1 -0
  31. package/dist/config/schema.spec.d.ts +2 -0
  32. package/dist/config/schema.spec.d.ts.map +1 -0
  33. package/dist/config/schema.spec.js +180 -0
  34. package/dist/config/schema.spec.js.map +1 -0
  35. package/dist/gateway/agent-manager.d.ts +138 -0
  36. package/dist/gateway/agent-manager.d.ts.map +1 -0
  37. package/dist/gateway/agent-manager.js +532 -0
  38. package/dist/gateway/agent-manager.js.map +1 -0
  39. package/dist/gateway/api.d.ts +43 -0
  40. package/dist/gateway/api.d.ts.map +1 -0
  41. package/dist/gateway/api.js +256 -0
  42. package/dist/gateway/api.js.map +1 -0
  43. package/dist/gateway/api.spec.d.ts +2 -0
  44. package/dist/gateway/api.spec.d.ts.map +1 -0
  45. package/dist/gateway/api.spec.js +256 -0
  46. package/dist/gateway/api.spec.js.map +1 -0
  47. package/dist/gateway/audit.d.ts +38 -0
  48. package/dist/gateway/audit.d.ts.map +1 -0
  49. package/dist/gateway/audit.js +82 -0
  50. package/dist/gateway/audit.js.map +1 -0
  51. package/dist/gateway/audit.spec.d.ts +2 -0
  52. package/dist/gateway/audit.spec.d.ts.map +1 -0
  53. package/dist/gateway/audit.spec.js +212 -0
  54. package/dist/gateway/audit.spec.js.map +1 -0
  55. package/dist/gateway/gateway.d.ts +27 -0
  56. package/dist/gateway/gateway.d.ts.map +1 -0
  57. package/dist/gateway/gateway.js +158 -0
  58. package/dist/gateway/gateway.js.map +1 -0
  59. package/dist/gateway/policy.d.ts +27 -0
  60. package/dist/gateway/policy.d.ts.map +1 -0
  61. package/dist/gateway/policy.js +40 -0
  62. package/dist/gateway/policy.js.map +1 -0
  63. package/dist/gateway/policy.spec.d.ts +2 -0
  64. package/dist/gateway/policy.spec.d.ts.map +1 -0
  65. package/dist/gateway/policy.spec.js +121 -0
  66. package/dist/gateway/policy.spec.js.map +1 -0
  67. package/dist/gateway/provider-health.d.ts +83 -0
  68. package/dist/gateway/provider-health.d.ts.map +1 -0
  69. package/dist/gateway/provider-health.js +219 -0
  70. package/dist/gateway/provider-health.js.map +1 -0
  71. package/dist/gateway/provider-health.spec.d.ts +2 -0
  72. package/dist/gateway/provider-health.spec.d.ts.map +1 -0
  73. package/dist/gateway/provider-health.spec.js +278 -0
  74. package/dist/gateway/provider-health.spec.js.map +1 -0
  75. package/dist/gateway/session-settings.d.ts +62 -0
  76. package/dist/gateway/session-settings.d.ts.map +1 -0
  77. package/dist/gateway/session-settings.js +91 -0
  78. package/dist/gateway/session-settings.js.map +1 -0
  79. package/dist/gateway/session-settings.spec.d.ts +2 -0
  80. package/dist/gateway/session-settings.spec.d.ts.map +1 -0
  81. package/dist/gateway/session-settings.spec.js +141 -0
  82. package/dist/gateway/session-settings.spec.js.map +1 -0
  83. package/dist/gateway/sessions.d.ts +68 -0
  84. package/dist/gateway/sessions.d.ts.map +1 -0
  85. package/dist/gateway/sessions.js +177 -0
  86. package/dist/gateway/sessions.js.map +1 -0
  87. package/dist/gateway/sessions.spec.d.ts +2 -0
  88. package/dist/gateway/sessions.spec.d.ts.map +1 -0
  89. package/dist/gateway/sessions.spec.js +190 -0
  90. package/dist/gateway/sessions.spec.js.map +1 -0
  91. package/dist/index.d.ts +11 -0
  92. package/dist/index.d.ts.map +1 -0
  93. package/dist/index.js +10 -0
  94. package/dist/index.js.map +1 -0
  95. package/dist/install.d.ts +39 -0
  96. package/dist/install.d.ts.map +1 -0
  97. package/dist/install.js +144 -0
  98. package/dist/install.js.map +1 -0
  99. package/dist/sandbox/manager.d.ts +63 -0
  100. package/dist/sandbox/manager.d.ts.map +1 -0
  101. package/dist/sandbox/manager.js +294 -0
  102. package/dist/sandbox/manager.js.map +1 -0
  103. package/dist/skills/index.d.ts +2 -0
  104. package/dist/skills/index.d.ts.map +1 -0
  105. package/dist/skills/index.js +2 -0
  106. package/dist/skills/index.js.map +1 -0
  107. package/dist/skills/registry.d.ts +11 -0
  108. package/dist/skills/registry.d.ts.map +1 -0
  109. package/dist/skills/registry.js +86 -0
  110. package/dist/skills/registry.js.map +1 -0
  111. package/dist/skills/registry.spec.d.ts +2 -0
  112. package/dist/skills/registry.spec.d.ts.map +1 -0
  113. package/dist/skills/registry.spec.js +220 -0
  114. package/dist/skills/registry.spec.js.map +1 -0
  115. package/dist/socket/protocol.d.ts +21 -0
  116. package/dist/socket/protocol.d.ts.map +1 -0
  117. package/dist/socket/protocol.js +7 -0
  118. package/dist/socket/protocol.js.map +1 -0
  119. package/dist/socket/protocol.spec.d.ts +2 -0
  120. package/dist/socket/protocol.spec.d.ts.map +1 -0
  121. package/dist/socket/protocol.spec.js +135 -0
  122. package/dist/socket/protocol.spec.js.map +1 -0
  123. package/dist/socket/server.d.ts +21 -0
  124. package/dist/socket/server.d.ts.map +1 -0
  125. package/dist/socket/server.js +133 -0
  126. package/dist/socket/server.js.map +1 -0
  127. package/dist/socket/server.spec.d.ts +2 -0
  128. package/dist/socket/server.spec.d.ts.map +1 -0
  129. package/dist/socket/server.spec.js +333 -0
  130. package/dist/socket/server.spec.js.map +1 -0
  131. package/dist/test/fixtures.d.ts +47 -0
  132. package/dist/test/fixtures.d.ts.map +1 -0
  133. package/dist/test/fixtures.js +144 -0
  134. package/dist/test/fixtures.js.map +1 -0
  135. package/dist/toolkit/index.d.ts +4 -0
  136. package/dist/toolkit/index.d.ts.map +1 -0
  137. package/dist/toolkit/index.js +4 -0
  138. package/dist/toolkit/index.js.map +1 -0
  139. package/dist/toolkit/installer.d.ts +26 -0
  140. package/dist/toolkit/installer.d.ts.map +1 -0
  141. package/dist/toolkit/installer.js +247 -0
  142. package/dist/toolkit/installer.js.map +1 -0
  143. package/dist/toolkit/registry.d.ts +19 -0
  144. package/dist/toolkit/registry.d.ts.map +1 -0
  145. package/dist/toolkit/registry.js +119 -0
  146. package/dist/toolkit/registry.js.map +1 -0
  147. package/dist/toolkit/registry.spec.d.ts +2 -0
  148. package/dist/toolkit/registry.spec.d.ts.map +1 -0
  149. package/dist/toolkit/registry.spec.js +194 -0
  150. package/dist/toolkit/registry.spec.js.map +1 -0
  151. package/dist/toolkit/schema.d.ts +61 -0
  152. package/dist/toolkit/schema.d.ts.map +1 -0
  153. package/dist/toolkit/schema.js +116 -0
  154. package/dist/toolkit/schema.js.map +1 -0
  155. package/dist/toolkit/schema.spec.d.ts +2 -0
  156. package/dist/toolkit/schema.spec.d.ts.map +1 -0
  157. package/dist/toolkit/schema.spec.js +202 -0
  158. package/dist/toolkit/schema.spec.js.map +1 -0
  159. package/dist/tools/core.d.ts +10 -0
  160. package/dist/tools/core.d.ts.map +1 -0
  161. package/dist/tools/core.js +246 -0
  162. package/dist/tools/core.js.map +1 -0
  163. package/dist/tools/core.spec.d.ts +2 -0
  164. package/dist/tools/core.spec.d.ts.map +1 -0
  165. package/dist/tools/core.spec.js +315 -0
  166. package/dist/tools/core.spec.js.map +1 -0
  167. package/dist/tools/registry.d.ts +15 -0
  168. package/dist/tools/registry.d.ts.map +1 -0
  169. package/dist/tools/registry.js +62 -0
  170. package/dist/tools/registry.js.map +1 -0
  171. package/dist/tools/registry.spec.d.ts +2 -0
  172. package/dist/tools/registry.spec.d.ts.map +1 -0
  173. package/dist/tools/registry.spec.js +228 -0
  174. package/dist/tools/registry.spec.js.map +1 -0
  175. package/dist/tools/runner.d.ts +25 -0
  176. package/dist/tools/runner.d.ts.map +1 -0
  177. package/dist/tools/runner.js +35 -0
  178. package/dist/tools/runner.js.map +1 -0
  179. package/dist/tools/runner.spec.d.ts +2 -0
  180. package/dist/tools/runner.spec.d.ts.map +1 -0
  181. package/dist/tools/runner.spec.js +129 -0
  182. package/dist/tools/runner.spec.js.map +1 -0
  183. package/dist/types/session.d.ts +8 -0
  184. package/dist/types/session.d.ts.map +1 -0
  185. package/dist/types/session.js +23 -0
  186. package/dist/types/session.js.map +1 -0
  187. package/package.json +76 -0
  188. package/tools/README.md +1 -0
  189. package/tools/kv/README.md +150 -0
  190. package/tools/kv/index.ts +149 -0
  191. package/tools/kv/tool.json +23 -0
  192. package/tools/message/README.md +53 -0
  193. package/tools/message/index.ts +183 -0
  194. package/tools/message/tool.json +11 -0
@@ -0,0 +1,278 @@
1
+ import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
2
+ import { ProviderHealthTracker, extractRateLimitInfo, } from "./provider-health.js";
3
+ import { rmSync, existsSync } from "fs";
4
+ import { join } from "path";
5
+ import { tmpdir } from "os";
6
+ describe("ProviderHealthTracker", () => {
7
+ let tracker;
8
+ let testDataDir;
9
+ let originalHome;
10
+ beforeEach(() => {
11
+ // Create a unique temp directory for each test
12
+ testDataDir = join(tmpdir(), `beige-health-test-${Date.now()}-${Math.random().toString(36).slice(2)}`);
13
+ // Override HOME to use our temp directory
14
+ originalHome = process.env.HOME;
15
+ process.env.HOME = testDataDir;
16
+ // Create tracker which will use our temp HOME
17
+ tracker = new ProviderHealthTracker();
18
+ });
19
+ afterEach(() => {
20
+ // Restore original HOME
21
+ if (originalHome !== undefined) {
22
+ process.env.HOME = originalHome;
23
+ }
24
+ else {
25
+ delete process.env.HOME;
26
+ }
27
+ // Clean up temp directory
28
+ if (existsSync(testDataDir)) {
29
+ rmSync(testDataDir, { recursive: true, force: true });
30
+ }
31
+ });
32
+ describe("isCoolingDown", () => {
33
+ it("returns false when no cooldown is set", () => {
34
+ expect(tracker.isCoolingDown("anthropic", "claude-sonnet")).toBe(false);
35
+ });
36
+ it("returns true when provider is in cooldown", () => {
37
+ tracker.markRateLimited("anthropic", "claude-sonnet", 60_000);
38
+ expect(tracker.isCoolingDown("anthropic", "claude-sonnet")).toBe(true);
39
+ });
40
+ it("returns false after cooldown expires", async () => {
41
+ vi.useFakeTimers();
42
+ tracker.markRateLimited("anthropic", "claude-sonnet", 100); // 100ms cooldown
43
+ expect(tracker.isCoolingDown("anthropic", "claude-sonnet")).toBe(true);
44
+ vi.advanceTimersByTime(150);
45
+ expect(tracker.isCoolingDown("anthropic", "claude-sonnet")).toBe(false);
46
+ vi.useRealTimers();
47
+ });
48
+ it("tracks different providers independently", () => {
49
+ tracker.markRateLimited("anthropic", "claude-sonnet", 60_000);
50
+ expect(tracker.isCoolingDown("anthropic", "claude-sonnet")).toBe(true);
51
+ expect(tracker.isCoolingDown("openai", "gpt-4")).toBe(false);
52
+ });
53
+ it("tracks different models independently", () => {
54
+ tracker.markRateLimited("anthropic", "claude-sonnet", 60_000);
55
+ expect(tracker.isCoolingDown("anthropic", "claude-sonnet")).toBe(true);
56
+ expect(tracker.isCoolingDown("anthropic", "claude-opus")).toBe(false);
57
+ });
58
+ });
59
+ describe("getRemainingCooldown", () => {
60
+ it("returns 0 when not cooling down", () => {
61
+ expect(tracker.getRemainingCooldown("anthropic", "claude-sonnet")).toBe(0);
62
+ });
63
+ it("returns remaining time in milliseconds", () => {
64
+ vi.useFakeTimers();
65
+ tracker.markRateLimited("anthropic", "claude-sonnet", 60_000);
66
+ const remaining = tracker.getRemainingCooldown("anthropic", "claude-sonnet");
67
+ expect(remaining).toBeGreaterThan(59_000);
68
+ expect(remaining).toBeLessThanOrEqual(60_000);
69
+ vi.advanceTimersByTime(30_000);
70
+ const remainingAfter = tracker.getRemainingCooldown("anthropic", "claude-sonnet");
71
+ expect(remainingAfter).toBeGreaterThan(29_000);
72
+ expect(remainingAfter).toBeLessThanOrEqual(30_000);
73
+ vi.useRealTimers();
74
+ });
75
+ });
76
+ describe("markRateLimited", () => {
77
+ it("sets cooldown with custom retry-after", () => {
78
+ tracker.markRateLimited("anthropic", "claude-sonnet", 120_000);
79
+ const remaining = tracker.getRemainingCooldown("anthropic", "claude-sonnet");
80
+ expect(remaining).toBeGreaterThan(119_000);
81
+ });
82
+ it("uses default cooldown when no retry-after provided", () => {
83
+ tracker.markRateLimited("anthropic", "claude-sonnet");
84
+ const remaining = tracker.getRemainingCooldown("anthropic", "claude-sonnet");
85
+ // Default is 30 minutes = 1,800,000 ms
86
+ expect(remaining).toBeGreaterThan(1_700_000);
87
+ });
88
+ it("stores error message", () => {
89
+ tracker.markRateLimited("anthropic", "claude-sonnet", 60_000, "Rate limit exceeded");
90
+ const entry = tracker.get("anthropic", "claude-sonnet");
91
+ expect(entry?.lastError).toBe("Rate limit exceeded");
92
+ });
93
+ it("increments consecutive failures", () => {
94
+ tracker.markRateLimited("anthropic", "claude-sonnet");
95
+ tracker.markRateLimited("anthropic", "claude-sonnet");
96
+ const entry = tracker.get("anthropic", "claude-sonnet");
97
+ expect(entry?.consecutiveFailures).toBe(2);
98
+ });
99
+ });
100
+ describe("markFailed", () => {
101
+ it("increments consecutive failures without setting cooldown", () => {
102
+ tracker.markFailed("anthropic", "claude-sonnet", "Connection error");
103
+ expect(tracker.isCoolingDown("anthropic", "claude-sonnet")).toBe(false);
104
+ const entry = tracker.get("anthropic", "claude-sonnet");
105
+ expect(entry?.consecutiveFailures).toBe(1);
106
+ expect(entry?.lastError).toBe("Connection error");
107
+ });
108
+ });
109
+ describe("markHealthy", () => {
110
+ it("clears consecutive failures", () => {
111
+ tracker.markRateLimited("anthropic", "claude-sonnet");
112
+ tracker.markHealthy("anthropic", "claude-sonnet");
113
+ const entry = tracker.get("anthropic", "claude-sonnet");
114
+ expect(entry?.consecutiveFailures).toBe(0);
115
+ });
116
+ it("clears rate limit info", () => {
117
+ tracker.markRateLimited("anthropic", "claude-sonnet", 60_000);
118
+ tracker.markHealthy("anthropic", "claude-sonnet");
119
+ expect(tracker.isCoolingDown("anthropic", "claude-sonnet")).toBe(false);
120
+ const entry = tracker.get("anthropic", "claude-sonnet");
121
+ expect(entry?.retryAfter).toBeUndefined();
122
+ expect(entry?.rateLimitedAt).toBeUndefined();
123
+ });
124
+ it("clears error message", () => {
125
+ tracker.markRateLimited("anthropic", "claude-sonnet", 60_000, "Error");
126
+ tracker.markHealthy("anthropic", "claude-sonnet");
127
+ const entry = tracker.get("anthropic", "claude-sonnet");
128
+ expect(entry?.lastError).toBeUndefined();
129
+ });
130
+ it("does nothing for unknown provider/model", () => {
131
+ // Should not throw
132
+ tracker.markHealthy("unknown", "unknown");
133
+ });
134
+ });
135
+ describe("clearCooldown", () => {
136
+ it("clears cooldown but keeps failure count", () => {
137
+ tracker.markRateLimited("anthropic", "claude-sonnet", 60_000);
138
+ tracker.clearCooldown("anthropic", "claude-sonnet");
139
+ expect(tracker.isCoolingDown("anthropic", "claude-sonnet")).toBe(false);
140
+ const entry = tracker.get("anthropic", "claude-sonnet");
141
+ expect(entry?.consecutiveFailures).toBe(1);
142
+ });
143
+ });
144
+ describe("getCoolingDown", () => {
145
+ it("returns all providers currently in cooldown", () => {
146
+ tracker.markRateLimited("anthropic", "claude-sonnet", 60_000);
147
+ tracker.markRateLimited("openai", "gpt-4", 60_000);
148
+ const cooling = tracker.getCoolingDown();
149
+ expect(cooling.length).toBe(2);
150
+ expect(cooling.map((c) => `${c.provider}/${c.model}`)).toContain("anthropic/claude-sonnet");
151
+ expect(cooling.map((c) => `${c.provider}/${c.model}`)).toContain("openai/gpt-4");
152
+ });
153
+ it("excludes providers that are not in cooldown", () => {
154
+ tracker.markRateLimited("anthropic", "claude-sonnet", 60_000);
155
+ const cooling = tracker.getCoolingDown();
156
+ expect(cooling.length).toBe(1);
157
+ expect(cooling[0].provider).toBe("anthropic");
158
+ });
159
+ it("excludes expired cooldowns", async () => {
160
+ vi.useFakeTimers();
161
+ tracker.markRateLimited("anthropic", "claude-sonnet", 100);
162
+ vi.advanceTimersByTime(150);
163
+ const cooling = tracker.getCoolingDown();
164
+ expect(cooling.length).toBe(0);
165
+ vi.useRealTimers();
166
+ });
167
+ });
168
+ });
169
+ describe("extractRateLimitInfo", () => {
170
+ describe("HTTP status detection", () => {
171
+ it("detects 429 status as rate limit", () => {
172
+ const error = { status: 429 };
173
+ const info = extractRateLimitInfo(error);
174
+ expect(info.isRateLimit).toBe(true);
175
+ });
176
+ it("detects 429 statusCode as rate limit", () => {
177
+ const error = { statusCode: 429 };
178
+ const info = extractRateLimitInfo(error);
179
+ expect(info.isRateLimit).toBe(true);
180
+ });
181
+ it("extracts retry-after from headers (seconds)", () => {
182
+ const error = {
183
+ status: 429,
184
+ headers: { "retry-after": "60" },
185
+ };
186
+ const info = extractRateLimitInfo(error);
187
+ expect(info.isRateLimit).toBe(true);
188
+ expect(info.retryAfterMs).toBe(60_000);
189
+ });
190
+ it("extracts retry-after from headers (numeric)", () => {
191
+ const error = {
192
+ status: 429,
193
+ headers: { "retry-after": 120 },
194
+ };
195
+ const info = extractRateLimitInfo(error);
196
+ expect(info.isRateLimit).toBe(true);
197
+ expect(info.retryAfterMs).toBe(120_000);
198
+ });
199
+ });
200
+ describe("error message patterns", () => {
201
+ it("detects 'rate_limit' in error type", () => {
202
+ const error = { error: { type: "rate_limit_error" } };
203
+ const info = extractRateLimitInfo(error);
204
+ expect(info.isRateLimit).toBe(true);
205
+ });
206
+ it("detects 'rate limit' in error message", () => {
207
+ const error = { message: "Rate limit exceeded. Please retry." };
208
+ const info = extractRateLimitInfo(error);
209
+ expect(info.isRateLimit).toBe(true);
210
+ });
211
+ it("detects 'too many requests' in error message", () => {
212
+ const error = { message: "Too many requests" };
213
+ const info = extractRateLimitInfo(error);
214
+ expect(info.isRateLimit).toBe(true);
215
+ });
216
+ it("detects 'overloaded' in error message", () => {
217
+ const error = { message: "API is overloaded" };
218
+ const info = extractRateLimitInfo(error);
219
+ expect(info.isRateLimit).toBe(true);
220
+ });
221
+ it("detects 'capacity' in error message", () => {
222
+ const error = { error: { message: "Insufficient capacity" } };
223
+ const info = extractRateLimitInfo(error);
224
+ expect(info.isRateLimit).toBe(true);
225
+ });
226
+ it("detects 'temporarily unavailable' in error message", () => {
227
+ const error = { message: "Service temporarily unavailable" };
228
+ const info = extractRateLimitInfo(error);
229
+ expect(info.isRateLimit).toBe(true);
230
+ });
231
+ });
232
+ describe("non-rate-limit errors", () => {
233
+ it("returns false for generic errors", () => {
234
+ const error = { message: "Internal server error", status: 500 };
235
+ const info = extractRateLimitInfo(error);
236
+ expect(info.isRateLimit).toBe(false);
237
+ });
238
+ it("returns false for auth errors", () => {
239
+ const error = { message: "Invalid API key", status: 401 };
240
+ const info = extractRateLimitInfo(error);
241
+ expect(info.isRateLimit).toBe(false);
242
+ });
243
+ it("returns false for null/undefined", () => {
244
+ expect(extractRateLimitInfo(null).isRateLimit).toBe(false);
245
+ expect(extractRateLimitInfo(undefined).isRateLimit).toBe(false);
246
+ });
247
+ it("returns false for non-object errors", () => {
248
+ expect(extractRateLimitInfo("error string").isRateLimit).toBe(false);
249
+ expect(extractRateLimitInfo(123).isRateLimit).toBe(false);
250
+ });
251
+ });
252
+ describe("retry-after parsing", () => {
253
+ it("parses numeric retry-after", () => {
254
+ const error = { status: 429, headers: { "retry-after": 30 } };
255
+ const info = extractRateLimitInfo(error);
256
+ expect(info.retryAfterMs).toBe(30_000);
257
+ });
258
+ it("parses string numeric retry-after", () => {
259
+ const error = { status: 429, headers: { "retry-after": "45" } };
260
+ const info = extractRateLimitInfo(error);
261
+ expect(info.retryAfterMs).toBe(45_000);
262
+ });
263
+ it("handles missing retry-after", () => {
264
+ const error = { status: 429 };
265
+ const info = extractRateLimitInfo(error);
266
+ expect(info.retryAfterMs).toBeUndefined();
267
+ });
268
+ it("handles Retry-After with capital letters", () => {
269
+ const error = {
270
+ status: 429,
271
+ headers: { "Retry-After": "60" },
272
+ };
273
+ const info = extractRateLimitInfo(error);
274
+ expect(info.retryAfterMs).toBe(60_000);
275
+ });
276
+ });
277
+ });
278
+ //# sourceMappingURL=provider-health.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider-health.spec.js","sourceRoot":"","sources":["../../src/gateway/provider-health.spec.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Per-session setting overrides.
3
+ *
4
+ * Settings are layered:
5
+ * system default → channel config default → session override
6
+ *
7
+ * Session overrides are stored in ~/.beige/sessions/session-settings.json
8
+ * and survive gateway restarts.
9
+ */
10
+ export interface SessionSettings {
11
+ /** Whether to forward tool-start notifications to the channel. */
12
+ verbose?: boolean;
13
+ /** Whether to stream responses in real-time (vs. send when complete). */
14
+ streaming?: boolean;
15
+ }
16
+ /**
17
+ * Known setting keys with their types (for type-safe access).
18
+ */
19
+ export interface KnownSettings {
20
+ verbose: boolean;
21
+ streaming: boolean;
22
+ }
23
+ export type SettingKey = keyof KnownSettings;
24
+ /**
25
+ * Persistent store for per-session setting overrides.
26
+ * Stored at ~/.beige/sessions/session-settings.json.
27
+ */
28
+ export declare class SessionSettingsStore {
29
+ private filePath;
30
+ private data;
31
+ constructor();
32
+ /**
33
+ * Get a single setting override for a session, or undefined if not set.
34
+ */
35
+ get<K extends SettingKey>(sessionKey: string, setting: K): KnownSettings[K] | undefined;
36
+ /**
37
+ * Set a setting override for a session.
38
+ */
39
+ set<K extends SettingKey>(sessionKey: string, setting: K, value: KnownSettings[K]): void;
40
+ /**
41
+ * Clear a specific setting override (revert to channel / system default).
42
+ */
43
+ clear<K extends SettingKey>(sessionKey: string, setting: K): void;
44
+ /**
45
+ * Clear all overrides for a session (e.g. when /new is called).
46
+ */
47
+ clearAll(sessionKey: string): void;
48
+ /**
49
+ * Get all overrides for a session.
50
+ */
51
+ getAll(sessionKey: string): SessionSettings;
52
+ private load;
53
+ private save;
54
+ }
55
+ /**
56
+ * Resolves the effective value of a setting by merging layers:
57
+ * 1. System default (hardcoded)
58
+ * 2. Channel config default (from config.json5)
59
+ * 3. Session override (from SessionSettingsStore)
60
+ */
61
+ export declare function resolveSessionSetting<K extends SettingKey>(setting: K, systemDefault: KnownSettings[K], channelDefault: KnownSettings[K] | undefined, sessionOverride: KnownSettings[K] | undefined): KnownSettings[K];
62
+ //# sourceMappingURL=session-settings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-settings.d.ts","sourceRoot":"","sources":["../../src/gateway/session-settings.ts"],"names":[],"mappings":"AAIA;;;;;;;;GAQG;AACH,MAAM,WAAW,eAAe;IAC9B,kEAAkE;IAClE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,yEAAyE;IACzE,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,MAAM,UAAU,GAAG,MAAM,aAAa,CAAC;AAE7C;;;GAGG;AACH,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,IAAI,CAAkC;;IAS9C;;OAEG;IACH,GAAG,CAAC,CAAC,SAAS,UAAU,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,GAAG,SAAS;IAQvF;;OAEG;IACH,GAAG,CAAC,CAAC,SAAS,UAAU,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,IAAI;IAQxF;;OAEG;IACH,KAAK,CAAC,CAAC,SAAS,UAAU,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,GAAG,IAAI;IASjE;;OAEG;IACH,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAOlC;;OAEG;IACH,MAAM,CAAC,UAAU,EAAE,MAAM,GAAG,eAAe;IAM3C,OAAO,CAAC,IAAI;IAQZ,OAAO,CAAC,IAAI;CAGb;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,SAAS,UAAU,EACxD,OAAO,EAAE,CAAC,EACV,aAAa,EAAE,aAAa,CAAC,CAAC,CAAC,EAC/B,cAAc,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,SAAS,EAC5C,eAAe,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,SAAS,GAC5C,aAAa,CAAC,CAAC,CAAC,CAIlB"}
@@ -0,0 +1,91 @@
1
+ import { readFileSync, writeFileSync, mkdirSync } from "fs";
2
+ import { resolve } from "path";
3
+ import { homedir } from "os";
4
+ /**
5
+ * Persistent store for per-session setting overrides.
6
+ * Stored at ~/.beige/sessions/session-settings.json.
7
+ */
8
+ export class SessionSettingsStore {
9
+ filePath;
10
+ data;
11
+ constructor() {
12
+ const dir = resolve(homedir(), ".beige", "sessions");
13
+ mkdirSync(dir, { recursive: true });
14
+ this.filePath = resolve(dir, "session-settings.json");
15
+ this.data = this.load();
16
+ }
17
+ /**
18
+ * Get a single setting override for a session, or undefined if not set.
19
+ */
20
+ get(sessionKey, setting) {
21
+ const overrides = this.data[sessionKey];
22
+ if (!overrides)
23
+ return undefined;
24
+ const value = overrides[setting];
25
+ // undefined means "not overridden"
26
+ return value;
27
+ }
28
+ /**
29
+ * Set a setting override for a session.
30
+ */
31
+ set(sessionKey, setting, value) {
32
+ if (!this.data[sessionKey]) {
33
+ this.data[sessionKey] = {};
34
+ }
35
+ this.data[sessionKey][setting] = value;
36
+ this.save();
37
+ }
38
+ /**
39
+ * Clear a specific setting override (revert to channel / system default).
40
+ */
41
+ clear(sessionKey, setting) {
42
+ if (!this.data[sessionKey])
43
+ return;
44
+ delete this.data[sessionKey][setting];
45
+ if (Object.keys(this.data[sessionKey]).length === 0) {
46
+ delete this.data[sessionKey];
47
+ }
48
+ this.save();
49
+ }
50
+ /**
51
+ * Clear all overrides for a session (e.g. when /new is called).
52
+ */
53
+ clearAll(sessionKey) {
54
+ if (this.data[sessionKey]) {
55
+ delete this.data[sessionKey];
56
+ this.save();
57
+ }
58
+ }
59
+ /**
60
+ * Get all overrides for a session.
61
+ */
62
+ getAll(sessionKey) {
63
+ return { ...this.data[sessionKey] };
64
+ }
65
+ // ── Private ────────────────────────────────────────────────────────
66
+ load() {
67
+ try {
68
+ return JSON.parse(readFileSync(this.filePath, "utf-8"));
69
+ }
70
+ catch {
71
+ return {};
72
+ }
73
+ }
74
+ save() {
75
+ writeFileSync(this.filePath, JSON.stringify(this.data, null, 2));
76
+ }
77
+ }
78
+ /**
79
+ * Resolves the effective value of a setting by merging layers:
80
+ * 1. System default (hardcoded)
81
+ * 2. Channel config default (from config.json5)
82
+ * 3. Session override (from SessionSettingsStore)
83
+ */
84
+ export function resolveSessionSetting(setting, systemDefault, channelDefault, sessionOverride) {
85
+ if (sessionOverride !== undefined)
86
+ return sessionOverride;
87
+ if (channelDefault !== undefined)
88
+ return channelDefault;
89
+ return systemDefault;
90
+ }
91
+ //# sourceMappingURL=session-settings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-settings.js","sourceRoot":"","sources":["../../src/gateway/session-settings.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=session-settings.spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-settings.spec.d.ts","sourceRoot":"","sources":["../../src/gateway/session-settings.spec.ts"],"names":[],"mappings":""}
@@ -0,0 +1,141 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from "vitest";
2
+ import { SessionSettingsStore, resolveSessionSetting, } from "./session-settings.js";
3
+ import { mkdirSync, rmSync } from "fs";
4
+ import { join } from "path";
5
+ import { tmpdir } from "os";
6
+ describe("SessionSettingsStore", () => {
7
+ let tempDir;
8
+ let store;
9
+ let originalHomedir;
10
+ beforeEach(() => {
11
+ tempDir = join(tmpdir(), `beige-settings-test-${Date.now()}`);
12
+ mkdirSync(tempDir, { recursive: true });
13
+ // Store temporarily overrides homedir behavior via the constructor
14
+ // We need to test the actual file operations, so we'll create a store
15
+ // and verify it works with our temp directory structure
16
+ store = new SessionSettingsStore();
17
+ });
18
+ afterEach(() => {
19
+ rmSync(tempDir, { recursive: true, force: true });
20
+ });
21
+ describe("get and set", () => {
22
+ it("returns undefined for unset settings", () => {
23
+ const value = store.get("test-session", "verbose");
24
+ expect(value).toBeUndefined();
25
+ });
26
+ it("sets and gets a setting", () => {
27
+ store.set("test-session", "verbose", true);
28
+ expect(store.get("test-session", "verbose")).toBe(true);
29
+ });
30
+ it("overwrites existing setting", () => {
31
+ store.set("test-session", "verbose", true);
32
+ store.set("test-session", "verbose", false);
33
+ expect(store.get("test-session", "verbose")).toBe(false);
34
+ });
35
+ it("tracks different sessions independently", () => {
36
+ store.set("session-1", "verbose", true);
37
+ store.set("session-2", "verbose", false);
38
+ expect(store.get("session-1", "verbose")).toBe(true);
39
+ expect(store.get("session-2", "verbose")).toBe(false);
40
+ });
41
+ it("tracks different settings for same session", () => {
42
+ store.set("test-session", "verbose", true);
43
+ store.set("test-session", "streaming", false);
44
+ expect(store.get("test-session", "verbose")).toBe(true);
45
+ expect(store.get("test-session", "streaming")).toBe(false);
46
+ });
47
+ });
48
+ describe("clear", () => {
49
+ it("clears a specific setting", () => {
50
+ store.set("test-session", "verbose", true);
51
+ store.set("test-session", "streaming", false);
52
+ store.clear("test-session", "verbose");
53
+ expect(store.get("test-session", "verbose")).toBeUndefined();
54
+ expect(store.get("test-session", "streaming")).toBe(false);
55
+ });
56
+ it("is safe to call on non-existent setting", () => {
57
+ // Should not throw
58
+ store.clear("unknown-session", "verbose");
59
+ });
60
+ });
61
+ describe("clearAll", () => {
62
+ it("clears all settings for a session", () => {
63
+ store.set("test-session", "verbose", true);
64
+ store.set("test-session", "streaming", false);
65
+ store.clearAll("test-session");
66
+ expect(store.get("test-session", "verbose")).toBeUndefined();
67
+ expect(store.get("test-session", "streaming")).toBeUndefined();
68
+ });
69
+ it("is safe to call on non-existent session", () => {
70
+ // Should not throw
71
+ store.clearAll("unknown-session");
72
+ });
73
+ });
74
+ describe("getAll", () => {
75
+ it("returns all settings for a session", () => {
76
+ store.set("test-session", "verbose", true);
77
+ store.set("test-session", "streaming", false);
78
+ const all = store.getAll("test-session");
79
+ expect(all).toEqual({ verbose: true, streaming: false });
80
+ });
81
+ it("returns empty object for unknown session", () => {
82
+ const all = store.getAll("unknown-session");
83
+ expect(all).toEqual({});
84
+ });
85
+ it("returns a copy (not mutable reference)", () => {
86
+ store.set("test-session", "verbose", true);
87
+ const all = store.getAll("test-session");
88
+ all.verbose = false;
89
+ expect(store.get("test-session", "verbose")).toBe(true);
90
+ });
91
+ });
92
+ describe("persistence", () => {
93
+ it("persists settings to disk", () => {
94
+ store.set("test-session", "verbose", true);
95
+ // Create a new store to verify persistence
96
+ const newStore = new SessionSettingsStore();
97
+ expect(newStore.get("test-session", "verbose")).toBe(true);
98
+ });
99
+ it("persists cleared settings", () => {
100
+ store.set("test-session", "verbose", true);
101
+ store.clear("test-session", "verbose");
102
+ const newStore = new SessionSettingsStore();
103
+ expect(newStore.get("test-session", "verbose")).toBeUndefined();
104
+ });
105
+ });
106
+ });
107
+ describe("resolveSessionSetting", () => {
108
+ it("returns session override when set", () => {
109
+ const result = resolveSessionSetting("verbose", false, // system default
110
+ undefined, // channel default
111
+ true // session override
112
+ );
113
+ expect(result).toBe(true);
114
+ });
115
+ it("returns channel default when no session override", () => {
116
+ const result = resolveSessionSetting("verbose", false, // system default
117
+ true, // channel default
118
+ undefined // no session override
119
+ );
120
+ expect(result).toBe(true);
121
+ });
122
+ it("returns system default when no overrides", () => {
123
+ const result = resolveSessionSetting("verbose", false, // system default
124
+ undefined, undefined);
125
+ expect(result).toBe(false);
126
+ });
127
+ it("session override takes precedence over channel default", () => {
128
+ const result = resolveSessionSetting("verbose", false, // system default
129
+ true, // channel default
130
+ false // session override
131
+ );
132
+ expect(result).toBe(false);
133
+ });
134
+ it("works with streaming setting", () => {
135
+ const result = resolveSessionSetting("streaming", true, // system default
136
+ false, // channel default
137
+ undefined);
138
+ expect(result).toBe(false);
139
+ });
140
+ });
141
+ //# sourceMappingURL=session-settings.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-settings.spec.js","sourceRoot":"","sources":["../../src/gateway/session-settings.spec.ts"],"names":[],"mappings":"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"}