@townco/debugger 0.1.74 → 0.1.75
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.
- package/package.json +3 -3
- package/src/server.ts +106 -50
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@townco/debugger",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.75",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"engines": {
|
|
6
6
|
"bun": ">=1.3.0"
|
|
@@ -24,8 +24,8 @@
|
|
|
24
24
|
"@radix-ui/react-select": "^2.2.6",
|
|
25
25
|
"@radix-ui/react-slot": "^1.2.4",
|
|
26
26
|
"@radix-ui/react-tabs": "^1.1.13",
|
|
27
|
-
"@townco/otlp-server": "0.1.
|
|
28
|
-
"@townco/tsconfig": "0.1.
|
|
27
|
+
"@townco/otlp-server": "0.1.74",
|
|
28
|
+
"@townco/tsconfig": "0.1.116",
|
|
29
29
|
"@townco/ui": "^0.1.77",
|
|
30
30
|
"bun-plugin-tailwind": "^0.1.2",
|
|
31
31
|
"class-variance-authority": "^0.7.1",
|
package/src/server.ts
CHANGED
|
@@ -18,6 +18,62 @@ import type {
|
|
|
18
18
|
export const DEFAULT_DEBUGGER_PORT = 4000;
|
|
19
19
|
export const DEFAULT_OTLP_PORT = 4318;
|
|
20
20
|
|
|
21
|
+
/**
|
|
22
|
+
* Middleware to check HTTP Basic Auth credentials
|
|
23
|
+
*/
|
|
24
|
+
function requireBasicAuth<T extends Request = Request>(
|
|
25
|
+
handler: (req: T) => Response | Promise<Response>,
|
|
26
|
+
): (req: T) => Response | Promise<Response> {
|
|
27
|
+
return (req: T) => {
|
|
28
|
+
// Skip auth check for localhost
|
|
29
|
+
const url = new URL(req.url);
|
|
30
|
+
const isLocalhost =
|
|
31
|
+
url.hostname === "localhost" ||
|
|
32
|
+
url.hostname === "127.0.0.1" ||
|
|
33
|
+
url.hostname === "::1";
|
|
34
|
+
|
|
35
|
+
if (isLocalhost) {
|
|
36
|
+
return handler(req);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const username = Bun.env.BASIC_AUTH_USER;
|
|
40
|
+
const password = Bun.env.BASIC_AUTH_PASS;
|
|
41
|
+
|
|
42
|
+
// If credentials are not configured, allow access
|
|
43
|
+
if (!username || !password) {
|
|
44
|
+
return handler(req);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Check Authorization header
|
|
48
|
+
const authHeader = req.headers.get("Authorization");
|
|
49
|
+
if (!authHeader || !authHeader.startsWith("Basic ")) {
|
|
50
|
+
return new Response("Unauthorized", {
|
|
51
|
+
status: 401,
|
|
52
|
+
headers: {
|
|
53
|
+
"WWW-Authenticate": 'Basic realm="Debugger"',
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Decode and verify credentials
|
|
59
|
+
const base64Credentials = authHeader.slice(6); // Remove "Basic " prefix
|
|
60
|
+
const credentials = atob(base64Credentials);
|
|
61
|
+
const [providedUsername, providedPassword] = credentials.split(":");
|
|
62
|
+
|
|
63
|
+
if (providedUsername !== username || providedPassword !== password) {
|
|
64
|
+
return new Response("Unauthorized", {
|
|
65
|
+
status: 401,
|
|
66
|
+
headers: {
|
|
67
|
+
"WWW-Authenticate": 'Basic realm="Debugger"',
|
|
68
|
+
},
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Credentials valid, proceed with handler
|
|
73
|
+
return handler(req);
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
21
77
|
/**
|
|
22
78
|
* Creates the debugger API routes. Can be used standalone without starting a
|
|
23
79
|
* server.
|
|
@@ -39,13 +95,13 @@ export function createDebuggerRoutes(options: {
|
|
|
39
95
|
|
|
40
96
|
return defineRoutes({
|
|
41
97
|
"/api/config": {
|
|
42
|
-
GET() {
|
|
98
|
+
GET: requireBasicAuth(() => {
|
|
43
99
|
return Response.json({ agentName });
|
|
44
|
-
},
|
|
100
|
+
}),
|
|
45
101
|
},
|
|
46
102
|
|
|
47
103
|
"/api/reset-database": {
|
|
48
|
-
POST() {
|
|
104
|
+
POST: requireBasicAuth(() => {
|
|
49
105
|
try {
|
|
50
106
|
resetDb();
|
|
51
107
|
return new Response("Database reset successfully", { status: 200 });
|
|
@@ -56,11 +112,11 @@ export function createDebuggerRoutes(options: {
|
|
|
56
112
|
{ status: 500 },
|
|
57
113
|
);
|
|
58
114
|
}
|
|
59
|
-
},
|
|
115
|
+
}),
|
|
60
116
|
},
|
|
61
117
|
|
|
62
118
|
"/api/sessions": {
|
|
63
|
-
GET(req) {
|
|
119
|
+
GET: requireBasicAuth((req) => {
|
|
64
120
|
const url = new URL(req.url);
|
|
65
121
|
const limit = Number.parseInt(
|
|
66
122
|
url.searchParams.get("limit") || "1000",
|
|
@@ -72,11 +128,11 @@ export function createDebuggerRoutes(options: {
|
|
|
72
128
|
);
|
|
73
129
|
const sessions = db.listSessions(limit, offset);
|
|
74
130
|
return Response.json(sessions);
|
|
75
|
-
},
|
|
131
|
+
}),
|
|
76
132
|
},
|
|
77
133
|
|
|
78
134
|
"/api/traces": {
|
|
79
|
-
GET(req) {
|
|
135
|
+
GET: requireBasicAuth((req) => {
|
|
80
136
|
const url = new URL(req.url);
|
|
81
137
|
const limit = Number.parseInt(
|
|
82
138
|
url.searchParams.get("limit") || "50",
|
|
@@ -89,11 +145,11 @@ export function createDebuggerRoutes(options: {
|
|
|
89
145
|
const sessionId = url.searchParams.get("sessionId") || undefined;
|
|
90
146
|
const traces = db.listTraces(limit, offset, sessionId);
|
|
91
147
|
return Response.json(traces);
|
|
92
|
-
},
|
|
148
|
+
}),
|
|
93
149
|
},
|
|
94
150
|
|
|
95
151
|
"/api/traces/:traceId": {
|
|
96
|
-
GET(req) {
|
|
152
|
+
GET: requireBasicAuth((req) => {
|
|
97
153
|
const traceId = req.params.traceId;
|
|
98
154
|
const data = db.getTraceById(traceId);
|
|
99
155
|
if (!data.trace) {
|
|
@@ -102,11 +158,11 @@ export function createDebuggerRoutes(options: {
|
|
|
102
158
|
// Extract messages on the server side
|
|
103
159
|
const messages = extractTurnMessages(data.spans, data.logs);
|
|
104
160
|
return Response.json({ ...data, messages });
|
|
105
|
-
},
|
|
161
|
+
}),
|
|
106
162
|
},
|
|
107
163
|
|
|
108
164
|
"/api/session-conversation": {
|
|
109
|
-
GET(req) {
|
|
165
|
+
GET: requireBasicAuth((req) => {
|
|
110
166
|
const url = new URL(req.url);
|
|
111
167
|
const sessionId = url.searchParams.get("sessionId");
|
|
112
168
|
if (!sessionId) {
|
|
@@ -133,13 +189,13 @@ export function createDebuggerRoutes(options: {
|
|
|
133
189
|
});
|
|
134
190
|
|
|
135
191
|
return Response.json(conversation);
|
|
136
|
-
},
|
|
192
|
+
}),
|
|
137
193
|
},
|
|
138
194
|
|
|
139
195
|
// Town Hall API endpoints
|
|
140
196
|
|
|
141
197
|
"/api/agent-config": {
|
|
142
|
-
async
|
|
198
|
+
GET: requireBasicAuth(async () => {
|
|
143
199
|
const config = await fetchAgentConfig();
|
|
144
200
|
if (!config) {
|
|
145
201
|
return Response.json(
|
|
@@ -148,11 +204,11 @@ export function createDebuggerRoutes(options: {
|
|
|
148
204
|
);
|
|
149
205
|
}
|
|
150
206
|
return Response.json(config);
|
|
151
|
-
},
|
|
207
|
+
}),
|
|
152
208
|
},
|
|
153
209
|
|
|
154
210
|
"/api/available-models": {
|
|
155
|
-
GET() {
|
|
211
|
+
GET: requireBasicAuth(() => {
|
|
156
212
|
// List of supported models for comparison
|
|
157
213
|
const models = [
|
|
158
214
|
// Anthropic models
|
|
@@ -165,11 +221,11 @@ export function createDebuggerRoutes(options: {
|
|
|
165
221
|
"gemini-1.5-flash",
|
|
166
222
|
];
|
|
167
223
|
return Response.json({ models });
|
|
168
|
-
},
|
|
224
|
+
}),
|
|
169
225
|
},
|
|
170
226
|
|
|
171
227
|
"/api/session-first-message/:sessionId": {
|
|
172
|
-
GET(req) {
|
|
228
|
+
GET: requireBasicAuth((req) => {
|
|
173
229
|
const sessionId = req.params.sessionId;
|
|
174
230
|
|
|
175
231
|
// Query logs directly by session attribute to avoid race conditions
|
|
@@ -184,15 +240,15 @@ export function createDebuggerRoutes(options: {
|
|
|
184
240
|
}
|
|
185
241
|
|
|
186
242
|
return Response.json({ message });
|
|
187
|
-
},
|
|
243
|
+
}),
|
|
188
244
|
},
|
|
189
245
|
|
|
190
246
|
"/api/comparison-config": {
|
|
191
|
-
GET() {
|
|
247
|
+
GET: requireBasicAuth(() => {
|
|
192
248
|
const config = comparisonDb.getLatestConfig();
|
|
193
249
|
return Response.json(config);
|
|
194
|
-
},
|
|
195
|
-
async
|
|
250
|
+
}),
|
|
251
|
+
POST: requireBasicAuth(async (req) => {
|
|
196
252
|
try {
|
|
197
253
|
const body = await req.json();
|
|
198
254
|
const config: ComparisonConfig = {
|
|
@@ -214,11 +270,11 @@ export function createDebuggerRoutes(options: {
|
|
|
214
270
|
{ status: 400 },
|
|
215
271
|
);
|
|
216
272
|
}
|
|
217
|
-
},
|
|
273
|
+
}),
|
|
218
274
|
},
|
|
219
275
|
|
|
220
276
|
"/api/comparison-config/:configId": {
|
|
221
|
-
GET(req) {
|
|
277
|
+
GET: requireBasicAuth((req) => {
|
|
222
278
|
const configId = req.params.configId;
|
|
223
279
|
const config = comparisonDb.getConfig(configId);
|
|
224
280
|
if (!config) {
|
|
@@ -228,18 +284,18 @@ export function createDebuggerRoutes(options: {
|
|
|
228
284
|
);
|
|
229
285
|
}
|
|
230
286
|
return Response.json(config);
|
|
231
|
-
},
|
|
287
|
+
}),
|
|
232
288
|
},
|
|
233
289
|
|
|
234
290
|
"/api/comparison-session-ids": {
|
|
235
|
-
GET() {
|
|
291
|
+
GET: requireBasicAuth(() => {
|
|
236
292
|
const sessionIds = comparisonDb.getComparisonSessionIds();
|
|
237
293
|
return Response.json({ sessionIds });
|
|
238
|
-
},
|
|
294
|
+
}),
|
|
239
295
|
},
|
|
240
296
|
|
|
241
297
|
"/api/comparison-runs": {
|
|
242
|
-
GET(req) {
|
|
298
|
+
GET: requireBasicAuth((req) => {
|
|
243
299
|
const url = new URL(req.url);
|
|
244
300
|
const limit = Number.parseInt(
|
|
245
301
|
url.searchParams.get("limit") || "50",
|
|
@@ -258,11 +314,11 @@ export function createDebuggerRoutes(options: {
|
|
|
258
314
|
|
|
259
315
|
const runs = comparisonDb.listRuns(limit, offset);
|
|
260
316
|
return Response.json(runs);
|
|
261
|
-
},
|
|
317
|
+
}),
|
|
262
318
|
},
|
|
263
319
|
|
|
264
320
|
"/api/comparison-run/:runId": {
|
|
265
|
-
GET(req) {
|
|
321
|
+
GET: requireBasicAuth((req) => {
|
|
266
322
|
const runId = req.params.runId;
|
|
267
323
|
const run = comparisonDb.getRun(runId);
|
|
268
324
|
if (!run) {
|
|
@@ -318,11 +374,11 @@ export function createDebuggerRoutes(options: {
|
|
|
318
374
|
controlMetrics,
|
|
319
375
|
variantMetrics,
|
|
320
376
|
});
|
|
321
|
-
},
|
|
377
|
+
}),
|
|
322
378
|
},
|
|
323
379
|
|
|
324
380
|
"/api/run-comparison": {
|
|
325
|
-
async
|
|
381
|
+
POST: requireBasicAuth(async (req) => {
|
|
326
382
|
try {
|
|
327
383
|
const body = await req.json();
|
|
328
384
|
const { sessionId, configId } = body;
|
|
@@ -391,11 +447,11 @@ export function createDebuggerRoutes(options: {
|
|
|
391
447
|
{ status: 500 },
|
|
392
448
|
);
|
|
393
449
|
}
|
|
394
|
-
},
|
|
450
|
+
}),
|
|
395
451
|
},
|
|
396
452
|
|
|
397
453
|
"/api/comparison-run/:runId/update": {
|
|
398
|
-
async
|
|
454
|
+
POST: requireBasicAuth(async (req) => {
|
|
399
455
|
try {
|
|
400
456
|
const runId = req.params.runId;
|
|
401
457
|
const body = await req.json();
|
|
@@ -425,11 +481,11 @@ export function createDebuggerRoutes(options: {
|
|
|
425
481
|
{ status: 500 },
|
|
426
482
|
);
|
|
427
483
|
}
|
|
428
|
-
},
|
|
484
|
+
}),
|
|
429
485
|
},
|
|
430
486
|
|
|
431
487
|
"/api/session-metrics/:sessionId": {
|
|
432
|
-
async
|
|
488
|
+
GET: requireBasicAuth(async (req) => {
|
|
433
489
|
const sessionId = req.params.sessionId;
|
|
434
490
|
const url = new URL(req.url);
|
|
435
491
|
const model = url.searchParams.get("model") || "unknown";
|
|
@@ -452,11 +508,11 @@ export function createDebuggerRoutes(options: {
|
|
|
452
508
|
// Extract metrics
|
|
453
509
|
const metrics = extractSessionMetrics(traces, allSpans, model);
|
|
454
510
|
return Response.json(metrics);
|
|
455
|
-
},
|
|
511
|
+
}),
|
|
456
512
|
},
|
|
457
513
|
|
|
458
514
|
"/api/analyze-session/:sessionId": {
|
|
459
|
-
async
|
|
515
|
+
POST: requireBasicAuth(async (req) => {
|
|
460
516
|
const sessionId = req.params.sessionId;
|
|
461
517
|
|
|
462
518
|
try {
|
|
@@ -542,11 +598,11 @@ export function createDebuggerRoutes(options: {
|
|
|
542
598
|
{ status: 500 },
|
|
543
599
|
);
|
|
544
600
|
}
|
|
545
|
-
},
|
|
601
|
+
}),
|
|
546
602
|
},
|
|
547
603
|
|
|
548
604
|
"/api/analyze-all-sessions": {
|
|
549
|
-
async
|
|
605
|
+
POST: requireBasicAuth(async (req) => {
|
|
550
606
|
try {
|
|
551
607
|
const body = await req.json();
|
|
552
608
|
const { sessionIds } = body as { sessionIds: string[] };
|
|
@@ -705,11 +761,11 @@ export function createDebuggerRoutes(options: {
|
|
|
705
761
|
{ status: 500 },
|
|
706
762
|
);
|
|
707
763
|
}
|
|
708
|
-
},
|
|
764
|
+
}),
|
|
709
765
|
},
|
|
710
766
|
|
|
711
767
|
"/api/session-analyses": {
|
|
712
|
-
async
|
|
768
|
+
GET: requireBasicAuth(async (req) => {
|
|
713
769
|
try {
|
|
714
770
|
const url = new URL(req.url);
|
|
715
771
|
const sessionId = url.searchParams.get("sessionId");
|
|
@@ -750,11 +806,11 @@ export function createDebuggerRoutes(options: {
|
|
|
750
806
|
{ status: 500 },
|
|
751
807
|
);
|
|
752
808
|
}
|
|
753
|
-
},
|
|
809
|
+
}),
|
|
754
810
|
},
|
|
755
811
|
|
|
756
812
|
"/api/session-analyses/:sessionId/similar": {
|
|
757
|
-
async
|
|
813
|
+
GET: requireBasicAuth(async (req) => {
|
|
758
814
|
try {
|
|
759
815
|
const sessionId = req.params.sessionId;
|
|
760
816
|
const url = new URL(req.url);
|
|
@@ -792,12 +848,12 @@ export function createDebuggerRoutes(options: {
|
|
|
792
848
|
{ status: 500 },
|
|
793
849
|
);
|
|
794
850
|
}
|
|
795
|
-
},
|
|
851
|
+
}),
|
|
796
852
|
},
|
|
797
853
|
|
|
798
854
|
// Comparison analysis endpoints
|
|
799
855
|
"/api/analyze-comparison/:runId": {
|
|
800
|
-
async
|
|
856
|
+
POST: requireBasicAuth(async (req) => {
|
|
801
857
|
const runId = req.params.runId;
|
|
802
858
|
|
|
803
859
|
try {
|
|
@@ -902,11 +958,11 @@ export function createDebuggerRoutes(options: {
|
|
|
902
958
|
{ status: 500 },
|
|
903
959
|
);
|
|
904
960
|
}
|
|
905
|
-
},
|
|
961
|
+
}),
|
|
906
962
|
},
|
|
907
963
|
|
|
908
964
|
"/api/comparison-analysis/:runId": {
|
|
909
|
-
async
|
|
965
|
+
GET: requireBasicAuth(async (req) => {
|
|
910
966
|
try {
|
|
911
967
|
const runId = req.params.runId;
|
|
912
968
|
const analysis = comparisonDb.getComparisonAnalysis(runId);
|
|
@@ -931,11 +987,11 @@ export function createDebuggerRoutes(options: {
|
|
|
931
987
|
{ status: 500 },
|
|
932
988
|
);
|
|
933
989
|
}
|
|
934
|
-
},
|
|
990
|
+
}),
|
|
935
991
|
},
|
|
936
992
|
|
|
937
993
|
"/api/comparison-analysis/:runId/exists": {
|
|
938
|
-
async
|
|
994
|
+
GET: requireBasicAuth(async (req) => {
|
|
939
995
|
try {
|
|
940
996
|
const runId = req.params.runId;
|
|
941
997
|
const exists = comparisonDb.hasComparisonAnalysis(runId);
|
|
@@ -943,7 +999,7 @@ export function createDebuggerRoutes(options: {
|
|
|
943
999
|
} catch (_error) {
|
|
944
1000
|
return Response.json({ exists: false });
|
|
945
1001
|
}
|
|
946
|
-
},
|
|
1002
|
+
}),
|
|
947
1003
|
},
|
|
948
1004
|
});
|
|
949
1005
|
}
|