@tonyclaw/agent-inspector 2.0.23 → 2.0.25

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 (41) hide show
  1. package/.output/nitro.json +1 -1
  2. package/.output/public/assets/{CompareDrawer-DnYQtd8R.js → CompareDrawer-DVNvS0GQ.js} +1 -1
  3. package/.output/public/assets/ProxyViewerContainer-By3XtQhZ.js +115 -0
  4. package/.output/public/assets/{ReplayDialog-B-3V95xT.js → ReplayDialog-Cw6bN-NR.js} +1 -1
  5. package/.output/public/assets/{RequestAnatomy-CT8hLGLa.js → RequestAnatomy-DnIsirBE.js} +1 -1
  6. package/.output/public/assets/{ResponseView-DK3CYom0.js → ResponseView-ygsUs7FU.js} +1 -1
  7. package/.output/public/assets/{StreamingChunkSequence-D3jJutjp.js → StreamingChunkSequence-DMUn8qXi.js} +1 -1
  8. package/.output/public/assets/_sessionId-DoqvnFx7.js +1 -0
  9. package/.output/public/assets/index-B0YcFeL-.js +1 -0
  10. package/.output/public/assets/index-DsiKfWCp.css +1 -0
  11. package/.output/public/assets/{main-hF_572U6.js → main-kBQ49n13.js} +2 -2
  12. package/.output/server/{_sessionId-BqhNE2M8.mjs → _sessionId-CYKaI68v.mjs} +2 -2
  13. package/.output/server/_ssr/{CompareDrawer-C4LQW4S1.mjs → CompareDrawer-CHk4p41X.mjs} +2 -2
  14. package/.output/server/_ssr/{ProxyViewerContainer-BKInvawk.mjs → ProxyViewerContainer-Co9ENCKV.mjs} +276 -47
  15. package/.output/server/_ssr/{ReplayDialog-C3ZiRihL.mjs → ReplayDialog-BRs3fk8H.mjs} +3 -3
  16. package/.output/server/_ssr/{RequestAnatomy-DlVAPIQZ.mjs → RequestAnatomy-Cb68EeZz.mjs} +2 -2
  17. package/.output/server/_ssr/{ResponseView-nMS0rkxu.mjs → ResponseView-DGdbfEjs.mjs} +2 -2
  18. package/.output/server/_ssr/{StreamingChunkSequence-PDWqrNiO.mjs → StreamingChunkSequence-DptYgirK.mjs} +2 -2
  19. package/.output/server/_ssr/{index-Cd1zD-lo.mjs → index-Ef5mCuww.mjs} +2 -2
  20. package/.output/server/_ssr/index.mjs +2 -2
  21. package/.output/server/_ssr/{router-R9gm7_sh.mjs → router-Cvv7SJnd.mjs} +192 -15
  22. package/.output/server/{_tanstack-start-manifest_v-BnLVH_EX.mjs → _tanstack-start-manifest_v-DQoXxIFQ.mjs} +1 -1
  23. package/.output/server/index.mjs +56 -56
  24. package/package.json +1 -1
  25. package/src/components/ProxyViewer.tsx +11 -1
  26. package/src/components/ProxyViewerContainer.tsx +21 -15
  27. package/src/components/providers/ProviderForm.tsx +176 -16
  28. package/src/lib/export-logs.ts +54 -11
  29. package/src/lib/providerTestPrompt.ts +4 -4
  30. package/src/lib/utils.ts +46 -0
  31. package/src/mcp/toolHandlers.ts +58 -8
  32. package/src/proxy/logFinalizer.ts +79 -1
  33. package/src/proxy/logIndex.ts +6 -1
  34. package/src/proxy/schemas.ts +3 -0
  35. package/src/proxy/store.ts +79 -2
  36. package/src/routes/api/logs.stream.ts +5 -2
  37. package/src/routes/api/logs.ts +4 -1
  38. package/.output/public/assets/ProxyViewerContainer-BTYGkg36.js +0 -115
  39. package/.output/public/assets/_sessionId-DpdfAzbo.js +0 -1
  40. package/.output/public/assets/index-780zTVwp.css +0 -1
  41. package/.output/public/assets/index-BpJNbm9G.js +0 -1
@@ -1,5 +1,5 @@
1
1
  import { r as reactExports, j as jsxRuntimeExports, a as React } from "../_libs/react.mjs";
2
- import { C as CapturedLogSchema, D as DEFAULT_CAPTURE_MODE, a as DEFAULT_SLOW_RESPONSE_THRESHOLD_SECONDS, b as DEFAULT_PROVIDER_TEST_TIMEOUT_SECONDS, c as DEFAULT_TIME_DISPLAY_FORMAT, d as RuntimeConfigSchema, P as ProviderConfigSchema, r as requestFormatForPath, j as createPendingProviderTestResults, k as ProviderTestResultsSchema, l as createFailedProviderTestResults, M as MAX_SLOW_RESPONSE_THRESHOLD_SECONDS, n as MAX_PROVIDER_TEST_TIMEOUT_SECONDS, T as TimeDisplayFormatSchema, m as maskApiKey, h as providerHasContextMetadata, i as findProviderModelMetadata, g as getSessionPath, p as parseOpenAIResponse, O as OpenAIRequestSchema, A as AnthropicResponseSchema$1, e as AnthropicRequestSchema, s as safeGetOwnProperty, o as resolveProviderContextWindow, K as KnowledgeCandidateSchema, f as stripClaudeCodeBillingHeader, q as isPlainRecord } from "./router-R9gm7_sh.mjs";
2
+ import { C as CapturedLogSchema, D as DEFAULT_CAPTURE_MODE, a as DEFAULT_SLOW_RESPONSE_THRESHOLD_SECONDS, b as DEFAULT_PROVIDER_TEST_TIMEOUT_SECONDS, c as DEFAULT_TIME_DISPLAY_FORMAT, d as RuntimeConfigSchema, P as ProviderConfigSchema, r as requestFormatForPath, j as createPendingProviderTestResults, k as ProviderTestResultsSchema, l as createFailedProviderTestResults, M as MAX_SLOW_RESPONSE_THRESHOLD_SECONDS, n as MAX_PROVIDER_TEST_TIMEOUT_SECONDS, T as TimeDisplayFormatSchema, m as maskApiKey, h as providerHasContextMetadata, i as findProviderModelMetadata, g as getSessionPath, p as parseOpenAIResponse, O as OpenAIRequestSchema, A as AnthropicResponseSchema$1, e as AnthropicRequestSchema, s as safeGetOwnProperty, o as resolveProviderContextWindow, K as KnowledgeCandidateSchema, f as stripClaudeCodeBillingHeader, q as isPlainRecord } from "./router-Cvv7SJnd.mjs";
3
3
  import { u as useSWR, a as useSWRConfig } from "../_libs/swr.mjs";
4
4
  import { J as JSZip } from "../_libs/jszip.mjs";
5
5
  import { c as clsx } from "../_libs/clsx.mjs";
@@ -299,6 +299,34 @@ const SECRET_TEXT_PATTERNS = [
299
299
  /\bghp_[A-Za-z0-9_]{12,}\b/g,
300
300
  /\bglpat-[A-Za-z0-9_-]{12,}\b/g
301
301
  ];
302
+ const MAX_EXPORT_LOGS = 200;
303
+ const MAX_EXPORT_TEXT_CHARS = 25e6;
304
+ const MAX_STREAMING_CHUNK_EXPORTS = 50;
305
+ function formatApproxSize(chars) {
306
+ if (chars < 1024) return `${chars} chars`;
307
+ if (chars < 1024 * 1024) return `${Math.ceil(chars / 1024)} KB`;
308
+ return `${Math.ceil(chars / (1024 * 1024))} MB`;
309
+ }
310
+ function estimateExportTextChars(logs) {
311
+ let total = 0;
312
+ for (const log of logs) {
313
+ total += log.rawRequestBody?.length ?? 0;
314
+ total += log.responseText?.length ?? 0;
315
+ }
316
+ return total;
317
+ }
318
+ function exportLimitMessage(logs) {
319
+ if (logs.length > MAX_EXPORT_LOGS) {
320
+ return `Export is limited to ${MAX_EXPORT_LOGS} logs at once. Narrow the filter and try again.`;
321
+ }
322
+ const estimatedChars = estimateExportTextChars(logs);
323
+ if (estimatedChars > MAX_EXPORT_TEXT_CHARS) {
324
+ return `Export is too large (${formatApproxSize(
325
+ estimatedChars
326
+ )} of text). Narrow the filter and try again.`;
327
+ }
328
+ return null;
329
+ }
302
330
  async function fetchStreamingChunks(logId) {
303
331
  try {
304
332
  const response = await fetch(`/api/logs/${logId}/chunks`);
@@ -340,8 +368,11 @@ function exportText(text, mode) {
340
368
  return mode === "redacted" ? redactJsonText(text) : text;
341
369
  }
342
370
  async function exportLogsAsZip(logs, mode = "redacted") {
371
+ const limitMessage = exportLimitMessage(logs);
372
+ if (limitMessage !== null) return { ok: false, message: limitMessage };
343
373
  const zip = new JSZip();
344
374
  const suffix = mode === "redacted" ? "redacted" : "raw";
375
+ const streamingLogs = logs.filter((log) => log.streaming).slice(0, MAX_STREAMING_CHUNK_EXPORTS);
345
376
  zip.file(
346
377
  "manifest.json",
347
378
  JSON.stringify(
@@ -350,7 +381,9 @@ async function exportLogsAsZip(logs, mode = "redacted") {
350
381
  mode,
351
382
  redacted: mode === "redacted",
352
383
  logCount: logs.length,
353
- logIds: logs.map((log) => log.id)
384
+ logIds: logs.map((log) => log.id),
385
+ streamingChunkExportLimit: MAX_STREAMING_CHUNK_EXPORTS,
386
+ streamingChunkLogIds: streamingLogs.map((log) => log.id)
354
387
  },
355
388
  null,
356
389
  2
@@ -364,15 +397,12 @@ async function exportLogsAsZip(logs, mode = "redacted") {
364
397
  zip.file(`#${log.id}.Response.json`, exportText(log.responseText, mode));
365
398
  }
366
399
  }
367
- const streamingLogs = logs.filter((log) => log.streaming);
368
- await Promise.allSettled(
369
- streamingLogs.map(async (log) => {
370
- const chunks = await fetchStreamingChunks(log.id);
371
- if (chunks !== null) {
372
- zip.file(`#${log.id}.SSE.Response.json`, exportText(chunks, mode));
373
- }
374
- })
375
- );
400
+ for (const log of streamingLogs) {
401
+ const chunks = await fetchStreamingChunks(log.id);
402
+ if (chunks !== null) {
403
+ zip.file(`#${log.id}.SSE.Response.json`, exportText(chunks, mode));
404
+ }
405
+ }
376
406
  const blob = await zip.generateAsync({ type: "blob" });
377
407
  const url = URL.createObjectURL(blob);
378
408
  const anchor = document.createElement("a");
@@ -382,6 +412,7 @@ async function exportLogsAsZip(logs, mode = "redacted") {
382
412
  anchor.click();
383
413
  document.body.removeChild(anchor);
384
414
  URL.revokeObjectURL(url);
415
+ return { ok: true };
385
416
  }
386
417
  function formatTimestamp(iso, format) {
387
418
  switch (format) {
@@ -411,6 +442,48 @@ function formatContextWindowTokens(count) {
411
442
  }
412
443
  return (count / 1024).toFixed(1).replace(/\.0$/, "") + "K";
413
444
  }
445
+ function formatExactContextUnit(count, multiplier, unit) {
446
+ const tenths = count * 10;
447
+ if (!Number.isSafeInteger(tenths) || tenths % multiplier !== 0) return null;
448
+ return (tenths / multiplier / 10).toFixed(1).replace(/\.0$/, "") + unit;
449
+ }
450
+ function formatContextWindowInput(count) {
451
+ if (!Number.isSafeInteger(count) || count <= 0) return count.toString();
452
+ if (count >= 1024 * 1024) {
453
+ const megaValue = formatExactContextUnit(count, 1024 * 1024, "M");
454
+ if (megaValue !== null) return megaValue;
455
+ }
456
+ const kiloValue = formatExactContextUnit(count, 1024, "K");
457
+ if (kiloValue !== null) return kiloValue;
458
+ return count.toString();
459
+ }
460
+ function contextWindowUnitMultiplier(unit) {
461
+ if (unit === void 0 || unit === "") return 1;
462
+ switch (unit.toLowerCase()) {
463
+ case "k":
464
+ return 1024;
465
+ case "m":
466
+ return 1024 * 1024;
467
+ default:
468
+ return null;
469
+ }
470
+ }
471
+ function parseContextWindowTokensInput(value) {
472
+ const trimmed = value.trim().replaceAll(",", "");
473
+ if (trimmed === "") return null;
474
+ const match = /^(\d+(?:\.\d+)?)\s*([kKmM])?$/.exec(trimmed);
475
+ if (match === null) return null;
476
+ const amountText = match[1];
477
+ if (amountText === void 0) return null;
478
+ const amount = Number(amountText);
479
+ const unit = match[2];
480
+ const multiplier = contextWindowUnitMultiplier(unit);
481
+ if (!Number.isFinite(amount) || amount <= 0 || multiplier === null) return null;
482
+ if ((unit === void 0 || unit === "") && !Number.isInteger(amount)) return null;
483
+ const tokens = Math.round(amount * multiplier);
484
+ if (!Number.isSafeInteger(tokens) || tokens <= 0) return null;
485
+ return tokens;
486
+ }
414
487
  function getStatusCategory(status) {
415
488
  if (status === null) return "pending";
416
489
  if (status >= 200 && status < 300) return "success";
@@ -442,7 +515,7 @@ function useProviders() {
442
515
  mutate: response.mutate
443
516
  };
444
517
  }
445
- const version = "2.0.23";
518
+ const version = "2.0.25";
446
519
  const packageJson = {
447
520
  version
448
521
  };
@@ -1503,19 +1576,19 @@ function useCopyFeedback(text) {
1503
1576
  return { copied, copy };
1504
1577
  }
1505
1578
  const LazyCompareDrawer = reactExports.lazy(
1506
- () => import("./CompareDrawer-C4LQW4S1.mjs").then((m) => ({ default: m.CompareDrawer }))
1579
+ () => import("./CompareDrawer-CHk4p41X.mjs").then((m) => ({ default: m.CompareDrawer }))
1507
1580
  );
1508
1581
  const LazyReplayDialog = reactExports.lazy(
1509
- () => import("./ReplayDialog-C3ZiRihL.mjs").then((m) => ({ default: m.ReplayDialog }))
1582
+ () => import("./ReplayDialog-BRs3fk8H.mjs").then((m) => ({ default: m.ReplayDialog }))
1510
1583
  );
1511
1584
  const LazyRequestAnatomy = reactExports.lazy(
1512
- () => import("./RequestAnatomy-DlVAPIQZ.mjs").then((m) => ({ default: m.RequestAnatomy }))
1585
+ () => import("./RequestAnatomy-Cb68EeZz.mjs").then((m) => ({ default: m.RequestAnatomy }))
1513
1586
  );
1514
1587
  const LazyResponseView = reactExports.lazy(
1515
- () => import("./ResponseView-nMS0rkxu.mjs").then((m) => ({ default: m.ResponseView }))
1588
+ () => import("./ResponseView-DGdbfEjs.mjs").then((m) => ({ default: m.ResponseView }))
1516
1589
  );
1517
1590
  const LazyStreamingChunkSequence = reactExports.lazy(
1518
- () => import("./StreamingChunkSequence-PDWqrNiO.mjs").then((m) => ({
1591
+ () => import("./StreamingChunkSequence-DptYgirK.mjs").then((m) => ({
1519
1592
  default: m.StreamingChunkSequence
1520
1593
  }))
1521
1594
  );
@@ -6168,8 +6241,19 @@ const ZHIPU_MODELS = [
6168
6241
  "glm-4.5-airx",
6169
6242
  "glm-4.5-flash"
6170
6243
  ];
6244
+ const CONTEXT_WINDOW_UNSET = "__unset__";
6245
+ const CONTEXT_WINDOW_CUSTOM = "__custom__";
6246
+ const CONTEXT_WINDOW_PRESETS = [
6247
+ { value: "32K", label: "Small" },
6248
+ { value: "64K", label: "Standard" },
6249
+ { value: "128K", label: "Medium" },
6250
+ { value: "200K", label: "Long" },
6251
+ { value: "256K", label: "Extended" },
6252
+ { value: "512K", label: "Large" },
6253
+ { value: "1M", label: "Max" }
6254
+ ];
6171
6255
  function emptyMetadataDraft() {
6172
- return { contextWindow: "", outputLimit: "" };
6256
+ return { contextWindow: "", contextWindowMode: "unset", outputLimit: "" };
6173
6257
  }
6174
6258
  function normalizeModelName(value) {
6175
6259
  return value.trim().toLowerCase().replace(/\s+/g, "-");
@@ -6180,11 +6264,65 @@ function findModelMetadata(provider, model) {
6180
6264
  (metadata) => normalizeModelName(metadata.model) === normalized
6181
6265
  ) ?? null;
6182
6266
  }
6267
+ function findContextWindowPreset(value) {
6268
+ const tokens = parseContextWindowTokensInput(value);
6269
+ if (tokens === null) return null;
6270
+ for (const preset of CONTEXT_WINDOW_PRESETS) {
6271
+ if (parseContextWindowTokensInput(preset.value) === tokens) return preset.value;
6272
+ }
6273
+ return null;
6274
+ }
6275
+ function contextWindowModeForValue(value) {
6276
+ if (value.trim() === "") return "unset";
6277
+ return findContextWindowPreset(value) !== null ? "preset" : "custom";
6278
+ }
6279
+ function selectedContextWindowPresetValue(draft) {
6280
+ switch (draft.contextWindowMode) {
6281
+ case "unset":
6282
+ return CONTEXT_WINDOW_UNSET;
6283
+ case "custom":
6284
+ return CONTEXT_WINDOW_CUSTOM;
6285
+ case "preset":
6286
+ return findContextWindowPreset(draft.contextWindow) ?? CONTEXT_WINDOW_CUSTOM;
6287
+ }
6288
+ }
6289
+ function splitContextWindowEditorValue(value) {
6290
+ const trimmed = value.trim().replaceAll(",", "");
6291
+ if (trimmed === "") return { amount: "", unit: "K" };
6292
+ const match = /^(\d+(?:\.\d+)?)\s*([kKmM])?$/.exec(trimmed);
6293
+ if (match === null) return { amount: trimmed, unit: "K" };
6294
+ const amount = match[1];
6295
+ if (amount === void 0) return { amount: trimmed, unit: "K" };
6296
+ const unit = match[2];
6297
+ if (unit === void 0 || unit === "") return { amount, unit: "tokens" };
6298
+ switch (unit.toLowerCase()) {
6299
+ case "k":
6300
+ return { amount, unit: "K" };
6301
+ case "m":
6302
+ return { amount, unit: "M" };
6303
+ default:
6304
+ return { amount: trimmed, unit: "K" };
6305
+ }
6306
+ }
6307
+ function joinContextWindowEditorValue(amount, unit) {
6308
+ const trimmed = amount.trim();
6309
+ if (trimmed === "") return "";
6310
+ switch (unit) {
6311
+ case "K":
6312
+ return `${trimmed}K`;
6313
+ case "M":
6314
+ return `${trimmed}M`;
6315
+ case "tokens":
6316
+ return trimmed;
6317
+ }
6318
+ }
6183
6319
  function createMetadataDrafts(provider, models) {
6184
6320
  return models.map((model) => {
6185
6321
  const metadata = findModelMetadata(provider, model);
6322
+ const contextWindow = metadata?.contextWindow !== void 0 ? formatContextWindowInput(metadata.contextWindow) : "";
6186
6323
  return {
6187
- contextWindow: metadata?.contextWindow?.toString() ?? "",
6324
+ contextWindow,
6325
+ contextWindowMode: contextWindowModeForValue(contextWindow),
6188
6326
  outputLimit: metadata?.outputLimit?.toString() ?? ""
6189
6327
  };
6190
6328
  });
@@ -6312,10 +6450,10 @@ function ProviderForm({ provider, onSubmit, onCancel }) {
6312
6450
  newErrors.modelMetadataUrl = "Invalid URL format";
6313
6451
  }
6314
6452
  modelMetadataDrafts.forEach((draft, index) => {
6315
- const contextWindow = readPositiveIntegerInput(draft.contextWindow);
6453
+ const contextWindow = parseContextWindowTokensInput(draft.contextWindow);
6316
6454
  const outputLimit = readPositiveIntegerInput(draft.outputLimit);
6317
6455
  if (draft.contextWindow.trim() !== "" && contextWindow === null) {
6318
- newErrors[`modelMetadata.${index}.contextWindow`] = "Context window must be a positive integer";
6456
+ newErrors[`modelMetadata.${index}.contextWindow`] = "Context window must be a positive number, optionally using K or M";
6319
6457
  }
6320
6458
  if (draft.outputLimit.trim() !== "" && outputLimit === null) {
6321
6459
  newErrors[`modelMetadata.${index}.outputLimit`] = "Output limit must be a positive integer";
@@ -6352,6 +6490,48 @@ function ProviderForm({ provider, onSubmit, onCancel }) {
6352
6490
  return next;
6353
6491
  });
6354
6492
  }
6493
+ function updateContextWindowPreset(index, value) {
6494
+ switch (value) {
6495
+ case CONTEXT_WINDOW_UNSET:
6496
+ updateMetadataDraft(index, { contextWindow: "", contextWindowMode: "unset" });
6497
+ return;
6498
+ case CONTEXT_WINDOW_CUSTOM: {
6499
+ const current = modelMetadataDrafts[index] ?? emptyMetadataDraft();
6500
+ updateMetadataDraft(index, {
6501
+ contextWindow: current.contextWindow,
6502
+ contextWindowMode: "custom"
6503
+ });
6504
+ return;
6505
+ }
6506
+ default:
6507
+ updateMetadataDraft(index, { contextWindow: value, contextWindowMode: "preset" });
6508
+ return;
6509
+ }
6510
+ }
6511
+ function updateContextWindowAmount(index, amount) {
6512
+ const current = modelMetadataDrafts[index] ?? emptyMetadataDraft();
6513
+ const editorValue = splitContextWindowEditorValue(current.contextWindow);
6514
+ updateMetadataDraft(index, {
6515
+ contextWindow: joinContextWindowEditorValue(amount, editorValue.unit),
6516
+ contextWindowMode: "custom"
6517
+ });
6518
+ }
6519
+ function updateContextWindowUnit(index, unit) {
6520
+ const current = modelMetadataDrafts[index] ?? emptyMetadataDraft();
6521
+ const editorValue = splitContextWindowEditorValue(current.contextWindow);
6522
+ switch (unit) {
6523
+ case "K":
6524
+ case "M":
6525
+ case "tokens":
6526
+ updateMetadataDraft(index, {
6527
+ contextWindow: joinContextWindowEditorValue(editorValue.amount, unit),
6528
+ contextWindowMode: "custom"
6529
+ });
6530
+ return;
6531
+ default:
6532
+ return;
6533
+ }
6534
+ }
6355
6535
  function removeModel(index) {
6356
6536
  setModels((prev) => prev.filter((_, idx) => idx !== index));
6357
6537
  setModelMetadataDrafts((prev) => prev.filter((_, idx) => idx !== index));
@@ -6367,7 +6547,7 @@ function ProviderForm({ provider, onSubmit, onCancel }) {
6367
6547
  const trimmedModel = model.trim();
6368
6548
  if (trimmedModel === "") return;
6369
6549
  const draft = modelMetadataDrafts[index] ?? emptyMetadataDraft();
6370
- const contextWindow = readPositiveIntegerInput(draft.contextWindow);
6550
+ const contextWindow = parseContextWindowTokensInput(draft.contextWindow);
6371
6551
  const outputLimit = readPositiveIntegerInput(draft.outputLimit);
6372
6552
  if (contextWindow === null && outputLimit === null) return;
6373
6553
  const existing = findModelMetadata(provider, trimmedModel);
@@ -6517,6 +6697,8 @@ function ProviderForm({ provider, onSubmit, onCancel }) {
6517
6697
  const draft = modelMetadataDrafts[i] ?? emptyMetadataDraft();
6518
6698
  const contextWindowError = errors[`modelMetadata.${i}.contextWindow`];
6519
6699
  const outputLimitError = errors[`modelMetadata.${i}.outputLimit`];
6700
+ const contextWindowPresetValue = selectedContextWindowPresetValue(draft);
6701
+ const contextWindowEditorValue = splitContextWindowEditorValue(draft.contextWindow);
6520
6702
  return /* @__PURE__ */ jsxRuntimeExports.jsxs(
6521
6703
  "div",
6522
6704
  {
@@ -6593,20 +6775,55 @@ function ProviderForm({ provider, onSubmit, onCancel }) {
6593
6775
  )
6594
6776
  ] }),
6595
6777
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid gap-2 sm:grid-cols-2", children: [
6596
- /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "space-y-1 text-xs text-muted-foreground", children: [
6778
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1 text-xs text-muted-foreground", children: [
6597
6779
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Context Window" }),
6598
- /* @__PURE__ */ jsxRuntimeExports.jsx(
6599
- "input",
6780
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
6781
+ Select,
6600
6782
  {
6601
- type: "number",
6602
- min: 1,
6603
- step: 1e3,
6604
- value: draft.contextWindow,
6605
- onChange: (e) => updateMetadataDraft(i, { contextWindow: e.target.value }),
6606
- placeholder: "e.g. 1048576",
6607
- className: "w-full rounded-md border border-input bg-background px-3 py-2 font-mono text-xs text-foreground ring-offset-background placeholder:text-muted-foreground focus-visible:border-ring focus-visible:outline-ring focus-visible:ring-[3px]"
6783
+ value: contextWindowPresetValue,
6784
+ onValueChange: (value) => updateContextWindowPreset(i, value),
6785
+ children: [
6786
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SelectTrigger, { size: "sm", className: "w-full bg-background font-mono text-xs", children: /* @__PURE__ */ jsxRuntimeExports.jsx(SelectValue, {}) }),
6787
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(SelectContent, { className: "max-h-64", children: [
6788
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { value: CONTEXT_WINDOW_UNSET, children: "Not set" }),
6789
+ CONTEXT_WINDOW_PRESETS.map((preset) => /* @__PURE__ */ jsxRuntimeExports.jsxs(SelectItem, { value: preset.value, children: [
6790
+ preset.label,
6791
+ " · ",
6792
+ preset.value
6793
+ ] }, preset.value)),
6794
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { value: CONTEXT_WINDOW_CUSTOM, children: "Custom" })
6795
+ ] })
6796
+ ]
6608
6797
  }
6609
6798
  ),
6799
+ draft.contextWindowMode === "custom" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-[minmax(0,1fr)_5.75rem] gap-1.5", children: [
6800
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
6801
+ "input",
6802
+ {
6803
+ type: "text",
6804
+ inputMode: "decimal",
6805
+ value: contextWindowEditorValue.amount,
6806
+ onChange: (e) => updateContextWindowAmount(i, e.target.value),
6807
+ placeholder: "128",
6808
+ className: "w-full rounded-md border border-input bg-background px-3 py-2 font-mono text-xs text-foreground ring-offset-background placeholder:text-muted-foreground focus-visible:border-ring focus-visible:outline-ring focus-visible:ring-[3px]"
6809
+ }
6810
+ ),
6811
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
6812
+ Select,
6813
+ {
6814
+ value: contextWindowEditorValue.unit,
6815
+ onValueChange: (value) => updateContextWindowUnit(i, value),
6816
+ children: [
6817
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SelectTrigger, { size: "sm", className: "w-full bg-background font-mono text-xs", children: /* @__PURE__ */ jsxRuntimeExports.jsx(SelectValue, {}) }),
6818
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(SelectContent, { children: [
6819
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { value: "K", children: "K" }),
6820
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { value: "M", children: "M" }),
6821
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { value: "tokens", children: "tokens" })
6822
+ ] })
6823
+ ]
6824
+ }
6825
+ )
6826
+ ] }),
6610
6827
  contextWindowError !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "block text-destructive", children: contextWindowError })
6611
6828
  ] }),
6612
6829
  /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "space-y-1 text-xs text-muted-foreground", children: [
@@ -9440,6 +9657,7 @@ function ProxyViewer({
9440
9657
  const { totalIn, totalOut } = reactExports.useMemo(() => computeTokenSummary(logs), [logs]);
9441
9658
  const { providers } = useProviders();
9442
9659
  const [exporting, setExporting] = reactExports.useState(null);
9660
+ const [exportError, setExportError] = reactExports.useState(null);
9443
9661
  const [comparePair, setComparePair] = reactExports.useState(null);
9444
9662
  const [crabEntrancePhase, setCrabEntrancePhase] = reactExports.useState(
9445
9663
  "hidden"
@@ -9469,8 +9687,12 @@ function ProxyViewer({
9469
9687
  const handleExport = reactExports.useCallback(
9470
9688
  async (mode) => {
9471
9689
  setExporting(mode);
9690
+ setExportError(null);
9472
9691
  try {
9473
- await exportLogsAsZip(logs, mode);
9692
+ const result = await exportLogsAsZip(logs, mode);
9693
+ if (!result.ok) {
9694
+ setExportError(result.message);
9695
+ }
9474
9696
  } finally {
9475
9697
  setExporting(null);
9476
9698
  }
@@ -9658,7 +9880,8 @@ function ProxyViewer({
9658
9880
  children: "Clear"
9659
9881
  }
9660
9882
  )
9661
- ] })
9883
+ ] }),
9884
+ exportError !== null && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mb-4 rounded-md border border-destructive/30 bg-destructive/10 px-3 py-2 text-xs text-destructive", children: exportError })
9662
9885
  ] }),
9663
9886
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { children: logs.length === 0 ? selectedSession !== "__all__" ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-center text-muted-foreground py-16 space-y-4", children: [
9664
9887
  /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm font-medium", children: "Session not found" }),
@@ -9746,11 +9969,24 @@ function filterLogs(logs, selectedSession, selectedModel) {
9746
9969
  const DEBOUNCE_MS = 50;
9747
9970
  const HASH_SCROLL_ATTEMPTS = 12;
9748
9971
  const HASH_HIGHLIGHT_MS = 1800;
9972
+ const MAX_CLIENT_LOGS = 500;
9749
9973
  function buildLogsStreamUrl(sessionId) {
9750
9974
  if (sessionId === void 0) return "/api/logs/stream";
9751
9975
  const params = new URLSearchParams({ sessionId });
9752
9976
  return `/api/logs/stream?${params.toString()}`;
9753
9977
  }
9978
+ function buildLogIndex(logs) {
9979
+ const idx = /* @__PURE__ */ new Map();
9980
+ for (let i = 0; i < logs.length; i++) {
9981
+ const log = logs[i];
9982
+ if (log !== void 0) idx.set(log.id, i);
9983
+ }
9984
+ return idx;
9985
+ }
9986
+ function trimClientLogs(logs) {
9987
+ if (logs.length <= MAX_CLIENT_LOGS) return logs;
9988
+ return logs.slice(logs.length - MAX_CLIENT_LOGS);
9989
+ }
9754
9990
  function ProxyViewerContainer({
9755
9991
  initialSessionId
9756
9992
  } = {}) {
@@ -9787,6 +10023,8 @@ function ProxyViewerContainer({
9787
10023
  next = [...next, log];
9788
10024
  }
9789
10025
  }
10026
+ next = trimClientLogs(next);
10027
+ logIndexRef.current = buildLogIndex(next);
9790
10028
  return next;
9791
10029
  });
9792
10030
  }, []);
@@ -9821,13 +10059,9 @@ function ProxyViewerContainer({
9821
10059
  flushTimerRef.current = null;
9822
10060
  }
9823
10061
  pendingUpdatesRef.current = [];
9824
- const idx = /* @__PURE__ */ new Map();
9825
- for (let i = 0; i < update.logs.length; i++) {
9826
- const log = update.logs[i];
9827
- if (log !== void 0) idx.set(log.id, i);
9828
- }
9829
- logIndexRef.current = idx;
9830
- setAllLogs(update.logs);
10062
+ const nextLogs = trimClientLogs(update.logs);
10063
+ logIndexRef.current = buildLogIndex(nextLogs);
10064
+ setAllLogs(nextLogs);
9831
10065
  setError(null);
9832
10066
  } else if (update.type === "update") {
9833
10067
  scheduleUpdate(update.log);
@@ -9950,12 +10184,7 @@ function ProxyViewerContainer({
9950
10184
  const idSet = new Set(ids);
9951
10185
  setAllLogs((prev) => {
9952
10186
  const remaining = prev.filter((l) => !idSet.has(l.id));
9953
- const idx = /* @__PURE__ */ new Map();
9954
- for (let i = 0; i < remaining.length; i++) {
9955
- const log = remaining[i];
9956
- if (log !== void 0) idx.set(log.id, i);
9957
- }
9958
- logIndexRef.current = idx;
10187
+ logIndexRef.current = buildLogIndex(remaining);
9959
10188
  return remaining;
9960
10189
  });
9961
10190
  setError(null);
@@ -1,7 +1,7 @@
1
1
  import { r as reactExports, j as jsxRuntimeExports } from "../_libs/react.mjs";
2
- import { u as useProviders, D as Dialog, b as DialogContent, d as DialogHeader, e as DialogTitle, T as Tabs, h as TabsList, i as TabsTrigger, j as TabsContent, k as Button, l as TooltipProvider, m as Tooltip, n as TooltipTrigger, o as TooltipContent, p as dispatchLogFocusRequest } from "./ProxyViewerContainer-BKInvawk.mjs";
3
- import { ResponseView } from "./ResponseView-nMS0rkxu.mjs";
4
- import { C as CapturedLogSchema } from "./router-R9gm7_sh.mjs";
2
+ import { u as useProviders, D as Dialog, b as DialogContent, d as DialogHeader, e as DialogTitle, T as Tabs, h as TabsList, i as TabsTrigger, j as TabsContent, k as Button, l as TooltipProvider, m as Tooltip, n as TooltipTrigger, o as TooltipContent, p as dispatchLogFocusRequest } from "./ProxyViewerContainer-Co9ENCKV.mjs";
3
+ import { ResponseView } from "./ResponseView-DGdbfEjs.mjs";
4
+ import { C as CapturedLogSchema } from "./router-Cvv7SJnd.mjs";
5
5
  import "../_libs/jszip.mjs";
6
6
  import "../_libs/modelcontextprotocol__server.mjs";
7
7
  import { K as RotateCcw, ac as Braces, ad as Minimize2 } from "../_libs/lucide-react.mjs";
@@ -1,6 +1,6 @@
1
1
  import { r as reactExports, j as jsxRuntimeExports } from "../_libs/react.mjs";
2
- import { u as useProviders, q as analyzeContextIntelligence, f as formatTokens, l as TooltipProvider, c as cn, m as Tooltip, n as TooltipTrigger, o as TooltipContent, S as SegmentBar, R as ROLE_COLOR_CLASSES, A as ANATOMY_ROLE_LABELS, s as formatContextWindowTokens, C as CONTEXT_USAGE_THRESHOLDS } from "./ProxyViewerContainer-BKInvawk.mjs";
3
- import "./router-R9gm7_sh.mjs";
2
+ import { u as useProviders, q as analyzeContextIntelligence, f as formatTokens, l as TooltipProvider, c as cn, m as Tooltip, n as TooltipTrigger, o as TooltipContent, S as SegmentBar, R as ROLE_COLOR_CLASSES, A as ANATOMY_ROLE_LABELS, s as formatContextWindowTokens, C as CONTEXT_USAGE_THRESHOLDS } from "./ProxyViewerContainer-Co9ENCKV.mjs";
3
+ import "./router-Cvv7SJnd.mjs";
4
4
  import "../_libs/modelcontextprotocol__server.mjs";
5
5
  import "../_libs/jszip.mjs";
6
6
  import { ae as Info, b as ChevronDown, i as ChevronRight } from "../_libs/lucide-react.mjs";
@@ -1,6 +1,6 @@
1
1
  import { r as reactExports, j as jsxRuntimeExports } from "../_libs/react.mjs";
2
- import { g as getLogFormatAdapter, f as formatTokens, c as cn, t as getStatusCategory, B as Badge, v as Collapsible, w as CollapsibleTrigger, x as CollapsibleContent, y as ScrollArea, z as JsonViewer, E as safeJsonValue } from "./ProxyViewerContainer-BKInvawk.mjs";
3
- import "./router-R9gm7_sh.mjs";
2
+ import { g as getLogFormatAdapter, f as formatTokens, c as cn, t as getStatusCategory, B as Badge, v as Collapsible, w as CollapsibleTrigger, x as CollapsibleContent, y as ScrollArea, z as JsonViewer, E as safeJsonValue } from "./ProxyViewerContainer-Co9ENCKV.mjs";
3
+ import "./router-Cvv7SJnd.mjs";
4
4
  import "../_libs/modelcontextprotocol__server.mjs";
5
5
  import "../_libs/jszip.mjs";
6
6
  import { Z as Zap, o as TriangleAlert, af as CircleStop, B as Brain, b as ChevronDown, i as ChevronRight, T as Terminal } from "../_libs/lucide-react.mjs";
@@ -1,6 +1,6 @@
1
1
  import { r as reactExports, j as jsxRuntimeExports } from "../_libs/react.mjs";
2
- import { l as TooltipProvider, m as Tooltip, n as TooltipTrigger, B as Badge, o as TooltipContent, z as JsonViewer } from "./ProxyViewerContainer-BKInvawk.mjs";
3
- import "./router-R9gm7_sh.mjs";
2
+ import { l as TooltipProvider, m as Tooltip, n as TooltipTrigger, B as Badge, o as TooltipContent, z as JsonViewer } from "./ProxyViewerContainer-Co9ENCKV.mjs";
3
+ import "./router-Cvv7SJnd.mjs";
4
4
  import "../_libs/modelcontextprotocol__server.mjs";
5
5
  import "../_libs/jszip.mjs";
6
6
  import { b as ChevronDown, i as ChevronRight, L as LoaderCircle } from "../_libs/lucide-react.mjs";
@@ -1,6 +1,6 @@
1
- import { P as ProxyViewerContainer } from "./ProxyViewerContainer-BKInvawk.mjs";
1
+ import { P as ProxyViewerContainer } from "./ProxyViewerContainer-Co9ENCKV.mjs";
2
2
  import "../_libs/react.mjs";
3
- import "./router-R9gm7_sh.mjs";
3
+ import "./router-Cvv7SJnd.mjs";
4
4
  import "../_libs/modelcontextprotocol__server.mjs";
5
5
  import "../_libs/jszip.mjs";
6
6
  import "../_libs/swr.mjs";
@@ -198,7 +198,7 @@ function getResponse() {
198
198
  return event.res;
199
199
  }
200
200
  async function getStartManifest(matchedRoutes) {
201
- const { tsrStartManifest } = await import("../_tanstack-start-manifest_v-BnLVH_EX.mjs");
201
+ const { tsrStartManifest } = await import("../_tanstack-start-manifest_v-DQoXxIFQ.mjs");
202
202
  const startManifest = tsrStartManifest();
203
203
  const rootRoute = startManifest.routes[rootRouteId] = startManifest.routes[rootRouteId] || {};
204
204
  rootRoute.assets = rootRoute.assets || [];
@@ -767,7 +767,7 @@ let entriesPromise;
767
767
  let baseManifestPromise;
768
768
  let cachedFinalManifestPromise;
769
769
  async function loadEntries() {
770
- const routerEntry = await import("./router-R9gm7_sh.mjs").then((n) => n.t);
770
+ const routerEntry = await import("./router-Cvv7SJnd.mjs").then((n) => n.t);
771
771
  const startEntry = await import("./start-HYkvq4Ni.mjs");
772
772
  return { startEntry, routerEntry };
773
773
  }