@tonyclaw/agent-inspector 4.0.1 → 4.0.3
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/.output/backend/nitro.json +1 -1
- package/.output/cli.js +193 -110
- package/.output/server/_ssr/index.mjs +1 -1
- package/.output/server/_ssr/{router-CTHqmroT.mjs → router-ChILzhmz.mjs} +92 -4
- package/.output/server/index.mjs +1 -1
- package/.output/ui/assets/{CompareDrawer-L3n4J-Or.js → CompareDrawer-Co3cUF_I.js} +1 -1
- package/.output/ui/assets/{InspectorPet-D5o_3OZS.js → InspectorPet-jFcrL37X.js} +1 -1
- package/.output/ui/assets/{ProxyViewerContainer-Ocagx75S.js → ProxyViewerContainer-BPzt_VpM.js} +4 -4
- package/.output/ui/assets/{ReplayDialog-Bk7x1h-y.js → ReplayDialog-C6O_zuwI.js} +1 -1
- package/.output/ui/assets/{RequestAnatomy-U4lzL7Sc.js → RequestAnatomy-Ca6NvB7L.js} +1 -1
- package/.output/ui/assets/{ResponseView-LOWfvBLK.js → ResponseView-BzqKcveJ.js} +1 -1
- package/.output/ui/assets/{StreamingChunkSequence-DPfsrrXQ.js → StreamingChunkSequence-9pCZIsS_.js} +1 -1
- package/.output/ui/assets/{_sessionId-0MlWS-CO.js → _sessionId-BMP3KVGR.js} +1 -1
- package/.output/ui/assets/{_sessionId-OdX2Jvt1.js → _sessionId-y4eRoT1H.js} +1 -1
- package/.output/ui/assets/{index-Ea-c8hPg.js → index-CH5w-haG.js} +1 -1
- package/.output/ui/assets/{index-zVVS53Hd.js → index-CmocEhyU.js} +1 -1
- package/.output/ui/assets/{index-Du4qNOOt.js → index-DT8sMJ_n.js} +2 -2
- package/.output/ui/assets/{index-gvFj_9K6.js → index-bfsbIRZa.js} +1 -1
- package/.output/ui/assets/{json-viewer-C1WAMzg3.js → json-viewer-BfFOSDG5.js} +1 -1
- package/.output/ui/assets/{jszip.min-B8AKu2zm.js → jszip.min-BkbVkOsp.js} +1 -1
- package/.output/ui/index.html +1 -1
- package/package.json +5 -10
- package/src/assets/IDE/claudecode-color.svg +0 -1
- package/src/assets/IDE/codex-color.svg +0 -1
- package/src/assets/IDE/opencode.svg +0 -1
- package/src/assets/IDE/xiaomimimo.svg +0 -1
- package/src/assets/favicon.svg +0 -21
- package/src/assets/logos/alibaba.svg +0 -1
- package/src/assets/logos/anthropic.svg +0 -1
- package/src/assets/logos/claude-code.svg +0 -4
- package/src/assets/logos/deepseek.svg +0 -1
- package/src/assets/logos/minimax.jpeg +0 -0
- package/src/assets/logos/openai.svg +0 -1
- package/src/assets/logos/opencode.svg +0 -4
- package/src/assets/logos/qwen.webp +0 -0
- package/src/assets/logos/zhipuai.svg +0 -219
- package/src/backend/router.tsx +0 -36
- package/src/backend/routes/$.ts +0 -26
- package/src/backend/routes/__root.ts +0 -4
- package/src/backend/routes/api/-instances.ts +0 -7
- package/src/backend/routes/api/alerts.summary.ts +0 -28
- package/src/backend/routes/api/alerts.ts +0 -70
- package/src/backend/routes/api/config.paths.ts +0 -14
- package/src/backend/routes/api/config.ts +0 -73
- package/src/backend/routes/api/ecosystem.packages.$packageId.help.ts +0 -11
- package/src/backend/routes/api/ecosystem.packages.$packageId.install.ts +0 -11
- package/src/backend/routes/api/ecosystem.packages.$packageId.runner-presets.ts +0 -11
- package/src/backend/routes/api/ecosystem.packages.$packageId.upgrade.ts +0 -11
- package/src/backend/routes/api/ecosystem.packages.ts +0 -21
- package/src/backend/routes/api/ecosystem.recipes.$recipeId.run.ts +0 -11
- package/src/backend/routes/api/ecosystem.tasks.$taskId.ts +0 -16
- package/src/backend/routes/api/ecosystem.tasks.ts +0 -12
- package/src/backend/routes/api/groups.$groupId.evidence.ts +0 -55
- package/src/backend/routes/api/groups.$groupId.sessions.ts +0 -50
- package/src/backend/routes/api/groups.$groupId.ts +0 -93
- package/src/backend/routes/api/groups.ts +0 -79
- package/src/backend/routes/api/health.ts +0 -22
- package/src/backend/routes/api/instances.$name.connection.ts +0 -12
- package/src/backend/routes/api/instances.$name.restart.ts +0 -23
- package/src/backend/routes/api/instances.$name.start.ts +0 -18
- package/src/backend/routes/api/instances.$name.stop.ts +0 -23
- package/src/backend/routes/api/instances.$name.ts +0 -12
- package/src/backend/routes/api/instances.ts +0 -16
- package/src/backend/routes/api/knowledge.candidates.$candidateId.promote.ts +0 -32
- package/src/backend/routes/api/knowledge.candidates.$candidateId.ts +0 -50
- package/src/backend/routes/api/knowledge.candidates.ts +0 -10
- package/src/backend/routes/api/knowledge.project-context.ts +0 -29
- package/src/backend/routes/api/knowledge.search.ts +0 -62
- package/src/backend/routes/api/knowledge.sessions.$sessionId.candidates.ts +0 -26
- package/src/backend/routes/api/logs.$id.body.ts +0 -58
- package/src/backend/routes/api/logs.$id.chunks.ts +0 -37
- package/src/backend/routes/api/logs.$id.replay.ts +0 -297
- package/src/backend/routes/api/logs.$id.ts +0 -23
- package/src/backend/routes/api/logs.import.ts +0 -39
- package/src/backend/routes/api/logs.stream.ts +0 -174
- package/src/backend/routes/api/logs.ts +0 -214
- package/src/backend/routes/api/mcp.ts +0 -25
- package/src/backend/routes/api/models.ts +0 -10
- package/src/backend/routes/api/pi-agent.ts +0 -29
- package/src/backend/routes/api/providers.$providerId.model-metadata.ts +0 -173
- package/src/backend/routes/api/providers.$providerId.test.log.ts +0 -342
- package/src/backend/routes/api/providers.$providerId.ts +0 -111
- package/src/backend/routes/api/providers.export.ts +0 -44
- package/src/backend/routes/api/providers.import.ts +0 -81
- package/src/backend/routes/api/providers.scan.ts +0 -28
- package/src/backend/routes/api/providers.ts +0 -102
- package/src/backend/routes/api/runs.$runId.evidence.ts +0 -55
- package/src/backend/routes/api/runs.$runId.ts +0 -50
- package/src/backend/routes/api/runs.ts +0 -62
- package/src/backend/routes/api/runtime.ts +0 -46
- package/src/backend/routes/api/sessions.ts +0 -51
- package/src/backend/routes/api/storage.ts +0 -56
- package/src/backend/routes/livez.ts +0 -13
- package/src/backend/routes/metrics.ts +0 -14
- package/src/backend/routes/proxy/$.ts +0 -15
- package/src/backend/routes/readyz.ts +0 -18
- package/src/backend/start.ts +0 -10
- package/src/cli/alias.ts +0 -431
- package/src/cli/detect-tools.ts +0 -123
- package/src/cli/doctor.ts +0 -836
- package/src/cli/instance.ts +0 -1071
- package/src/cli/instanceApi.ts +0 -213
- package/src/cli/instanceArgs.ts +0 -301
- package/src/cli/instanceControl.ts +0 -191
- package/src/cli/instanceModel.ts +0 -276
- package/src/cli/instanceRegistry.ts +0 -731
- package/src/cli/networkHints.ts +0 -170
- package/src/cli/onboard.ts +0 -1668
- package/src/cli/onboardTarget.ts +0 -228
- package/src/cli/rustBackendPackage.ts +0 -458
- package/src/cli/startupOutput.ts +0 -16
- package/src/cli/templates/codex-skill-onboard.ts +0 -320
- package/src/cli/templates/command-onboard.ts +0 -25
- package/src/cli/templates/skill-onboard.ts +0 -625
- package/src/cli.ts +0 -1433
- package/src/components/OnboardingBanner.tsx +0 -115
- package/src/components/ProxyViewer.tsx +0 -2259
- package/src/components/ProxyViewerContainer.tsx +0 -1076
- package/src/components/alerts/AlertsDialog.tsx +0 -615
- package/src/components/clients/ClientLogo.tsx +0 -175
- package/src/components/ecosystem/AgentLabDialog.tsx +0 -947
- package/src/components/errors/SafeErrorBoundary.tsx +0 -201
- package/src/components/groups/GroupsDialog.tsx +0 -1304
- package/src/components/inspector-pet/InspectorPet.tsx +0 -398
- package/src/components/inspector-pet/InspectorPetCrab3D.tsx +0 -455
- package/src/components/inspector-pet/inspectorPetLogic.ts +0 -272
- package/src/components/pi-agent/PiAgentPanel.tsx +0 -446
- package/src/components/pi-agent/piAgentChatLogic.ts +0 -273
- package/src/components/providers/ImportWizardDialog.tsx +0 -281
- package/src/components/providers/ProviderCard.tsx +0 -347
- package/src/components/providers/ProviderForm.tsx +0 -1183
- package/src/components/providers/ProviderLogo.tsx +0 -122
- package/src/components/providers/ProviderTestResultsView.tsx +0 -734
- package/src/components/providers/ProvidersPanel.tsx +0 -714
- package/src/components/providers/SettingsDialog.tsx +0 -1042
- package/src/components/providers/providerFormCapabilities.ts +0 -36
- package/src/components/proxy-viewer/AgentTraceSummary.tsx +0 -902
- package/src/components/proxy-viewer/AnswerMarkdown.tsx +0 -51
- package/src/components/proxy-viewer/ApplicationBar.tsx +0 -123
- package/src/components/proxy-viewer/CompareDrawer.tsx +0 -984
- package/src/components/proxy-viewer/ConversationGroup.tsx +0 -208
- package/src/components/proxy-viewer/ConversationGroupList.tsx +0 -652
- package/src/components/proxy-viewer/ConversationHeader.tsx +0 -429
- package/src/components/proxy-viewer/LiveConnectionStatus.tsx +0 -186
- package/src/components/proxy-viewer/LogEntry.tsx +0 -1419
- package/src/components/proxy-viewer/LogEntryHeader.tsx +0 -596
- package/src/components/proxy-viewer/ProviderLogoStack.tsx +0 -57
- package/src/components/proxy-viewer/RawExportWarning.tsx +0 -77
- package/src/components/proxy-viewer/ReplayDialog.tsx +0 -636
- package/src/components/proxy-viewer/RequestToolsPanel.tsx +0 -299
- package/src/components/proxy-viewer/ResponseView.tsx +0 -202
- package/src/components/proxy-viewer/SessionLoadProgressBar.tsx +0 -61
- package/src/components/proxy-viewer/StreamingChunkSequence.tsx +0 -265
- package/src/components/proxy-viewer/ThreadConnector.tsx +0 -165
- package/src/components/proxy-viewer/ToolTraceEvents.tsx +0 -64
- package/src/components/proxy-viewer/TurnGroup.tsx +0 -383
- package/src/components/proxy-viewer/TurnGroupList.tsx +0 -156
- package/src/components/proxy-viewer/accessibility.ts +0 -8
- package/src/components/proxy-viewer/anatomy/RequestAnatomy.tsx +0 -887
- package/src/components/proxy-viewer/anatomy/SegmentBar.tsx +0 -222
- package/src/components/proxy-viewer/anatomy/contextIntelligence.ts +0 -737
- package/src/components/proxy-viewer/anatomy/sessionContextSummary.ts +0 -268
- package/src/components/proxy-viewer/anatomy/tokenEstimate.ts +0 -53
- package/src/components/proxy-viewer/anatomy/types.ts +0 -41
- package/src/components/proxy-viewer/anatomy/useAnatomyJump.ts +0 -114
- package/src/components/proxy-viewer/bodyHydration.ts +0 -123
- package/src/components/proxy-viewer/cacheTrend.ts +0 -50
- package/src/components/proxy-viewer/diff/DiffView.tsx +0 -321
- package/src/components/proxy-viewer/diff/computeDiff.ts +0 -178
- package/src/components/proxy-viewer/diff/index.ts +0 -3
- package/src/components/proxy-viewer/formats/anthropic/ContentBlocks.tsx +0 -194
- package/src/components/proxy-viewer/formats/anthropic/ResponseView.tsx +0 -81
- package/src/components/proxy-viewer/formats/anthropic/thinkingExtract.ts +0 -21
- package/src/components/proxy-viewer/formats/index.tsx +0 -47
- package/src/components/proxy-viewer/formats/openai/ResponseView.tsx +0 -442
- package/src/components/proxy-viewer/index.ts +0 -9
- package/src/components/proxy-viewer/lazy.ts +0 -41
- package/src/components/proxy-viewer/liveConnectionState.ts +0 -158
- package/src/components/proxy-viewer/log-formats/anthropic.ts +0 -191
- package/src/components/proxy-viewer/log-formats/index.ts +0 -23
- package/src/components/proxy-viewer/log-formats/openai.ts +0 -256
- package/src/components/proxy-viewer/log-formats/types.ts +0 -40
- package/src/components/proxy-viewer/log-formats/unknown.ts +0 -18
- package/src/components/proxy-viewer/logEntryVisibility.ts +0 -73
- package/src/components/proxy-viewer/logFocus.ts +0 -54
- package/src/components/proxy-viewer/proxyViewerContainerLogic.ts +0 -124
- package/src/components/proxy-viewer/proxyViewerLogic.ts +0 -488
- package/src/components/proxy-viewer/replayComparison.ts +0 -131
- package/src/components/proxy-viewer/requestDiff.ts +0 -277
- package/src/components/proxy-viewer/requestTools.ts +0 -220
- package/src/components/proxy-viewer/useCopyFeedback.ts +0 -38
- package/src/components/proxy-viewer/useKeyboardNavigation.ts +0 -232
- package/src/components/proxy-viewer/viewerState.ts +0 -176
- package/src/components/ui/badge.tsx +0 -47
- package/src/components/ui/button.tsx +0 -47
- package/src/components/ui/collapsible.tsx +0 -21
- package/src/components/ui/confirm-dialog.tsx +0 -51
- package/src/components/ui/crab-logo.tsx +0 -45
- package/src/components/ui/crab-variants.tsx +0 -467
- package/src/components/ui/dialog.tsx +0 -130
- package/src/components/ui/icon-trigger.ts +0 -2
- package/src/components/ui/json-viewer-bulk.ts +0 -132
- package/src/components/ui/json-viewer.tsx +0 -508
- package/src/components/ui/scroll-area.tsx +0 -54
- package/src/components/ui/select.tsx +0 -178
- package/src/components/ui/separator.tsx +0 -28
- package/src/components/ui/tabs.tsx +0 -88
- package/src/components/ui/tooltip.tsx +0 -51
- package/src/components/ui/transient-toast.tsx +0 -105
- package/src/contracts/anthropic.ts +0 -230
- package/src/contracts/index.ts +0 -59
- package/src/contracts/json.ts +0 -37
- package/src/contracts/log.ts +0 -139
- package/src/contracts/openai.ts +0 -267
- package/src/index.css +0 -11
- package/src/knowledge/candidateStore.ts +0 -94
- package/src/knowledge/distiller.ts +0 -98
- package/src/knowledge/openclawClient.ts +0 -161
- package/src/knowledge/openclawGatewayClient.ts +0 -249
- package/src/knowledge/openclawMarkdown.ts +0 -146
- package/src/knowledge/redactor.ts +0 -80
- package/src/knowledge/types.ts +0 -83
- package/src/lib/alertContract.ts +0 -76
- package/src/lib/apiClient.ts +0 -166
- package/src/lib/apiFormat.ts +0 -29
- package/src/lib/backendImplementation.ts +0 -16
- package/src/lib/basePath.ts +0 -107
- package/src/lib/browserRuntimeContract.ts +0 -124
- package/src/lib/browserRuntimeResolver.ts +0 -333
- package/src/lib/chunkLoadRecovery.ts +0 -83
- package/src/lib/claudeCodeStrip.ts +0 -98
- package/src/lib/clipboard.ts +0 -67
- package/src/lib/codingAgentEndpoints.ts +0 -54
- package/src/lib/ecosystemContract.ts +0 -130
- package/src/lib/export-logs.ts +0 -287
- package/src/lib/groupContract.ts +0 -166
- package/src/lib/instanceContract.ts +0 -239
- package/src/lib/jsonFile.ts +0 -46
- package/src/lib/logImportContract.ts +0 -12
- package/src/lib/managedInstance.ts +0 -112
- package/src/lib/mask.ts +0 -4
- package/src/lib/objectUtils.ts +0 -22
- package/src/lib/piAgentContract.ts +0 -102
- package/src/lib/providerContract.ts +0 -125
- package/src/lib/providerImportContract.ts +0 -27
- package/src/lib/providerModelMetadata.ts +0 -458
- package/src/lib/providerTestContract.ts +0 -170
- package/src/lib/providerTestPrompt.ts +0 -100
- package/src/lib/publicBasePathContext.ts +0 -137
- package/src/lib/resourceLimits.ts +0 -345
- package/src/lib/runContract.ts +0 -164
- package/src/lib/runtimeConfig.ts +0 -43
- package/src/lib/safeDiagnostic.ts +0 -38
- package/src/lib/safeFetch.ts +0 -508
- package/src/lib/serverPort.ts +0 -47
- package/src/lib/sessionInfoContract.ts +0 -78
- package/src/lib/sessionUrl.ts +0 -46
- package/src/lib/ssrfGuard.ts +0 -133
- package/src/lib/stopReason.ts +0 -130
- package/src/lib/themeMode.ts +0 -41
- package/src/lib/timeDisplay.ts +0 -22
- package/src/lib/toolTrace.ts +0 -290
- package/src/lib/uiScale.ts +0 -117
- package/src/lib/unknown.ts +0 -27
- package/src/lib/upstreamUrl.ts +0 -150
- package/src/lib/useAlerts.ts +0 -82
- package/src/lib/useGroupEvidence.ts +0 -37
- package/src/lib/useGroups.ts +0 -32
- package/src/lib/useOnboarding.ts +0 -93
- package/src/lib/useProviders.ts +0 -30
- package/src/lib/useStripConfig.ts +0 -154
- package/src/lib/useThemeMode.ts +0 -40
- package/src/lib/useUiScale.ts +0 -52
- package/src/lib/utils.ts +0 -78
- package/src/mcp/currentContext.ts +0 -65
- package/src/mcp/instanceHandlers.ts +0 -151
- package/src/mcp/loopback.ts +0 -88
- package/src/mcp/mode.ts +0 -75
- package/src/mcp/previewExtractor.ts +0 -233
- package/src/mcp/server.ts +0 -2274
- package/src/mcp/toolHandlers.ts +0 -1533
- package/src/proxy/alerts.ts +0 -664
- package/src/proxy/chunkStorage.ts +0 -123
- package/src/proxy/config.ts +0 -218
- package/src/proxy/constants.ts +0 -66
- package/src/proxy/dataDir.ts +0 -147
- package/src/proxy/ecosystemExecutionConfirmation.ts +0 -114
- package/src/proxy/ecosystemExecutionRoute.ts +0 -116
- package/src/proxy/ecosystemRegistry.ts +0 -296
- package/src/proxy/ecosystemTasks.ts +0 -415
- package/src/proxy/evidenceAnalysis.ts +0 -526
- package/src/proxy/evidenceExporter.ts +0 -235
- package/src/proxy/formats/anthropic/anthropicProvider.ts +0 -75
- package/src/proxy/formats/anthropic/handler.ts +0 -75
- package/src/proxy/formats/anthropic/index.ts +0 -13
- package/src/proxy/formats/anthropic/register.ts +0 -4
- package/src/proxy/formats/anthropic/schemas.ts +0 -6
- package/src/proxy/formats/anthropic/stream.ts +0 -205
- package/src/proxy/formats/handler.ts +0 -46
- package/src/proxy/formats/index.ts +0 -13
- package/src/proxy/formats/jsonSchema.ts +0 -2
- package/src/proxy/formats/openai/alibabaProvider.ts +0 -34
- package/src/proxy/formats/openai/codexMetadata.ts +0 -61
- package/src/proxy/formats/openai/handler.ts +0 -133
- package/src/proxy/formats/openai/index.ts +0 -33
- package/src/proxy/formats/openai/provider.ts +0 -50
- package/src/proxy/formats/openai/register.ts +0 -4
- package/src/proxy/formats/openai/schemas.ts +0 -25
- package/src/proxy/formats/openai/stream.ts +0 -600
- package/src/proxy/formats/openai/zhipuProvider.ts +0 -31
- package/src/proxy/formats/providerAdapter.ts +0 -50
- package/src/proxy/formats/providerRegistry.ts +0 -51
- package/src/proxy/formats/providers/index.ts +0 -3
- package/src/proxy/formats/registry.ts +0 -65
- package/src/proxy/groupEvidenceExporter.ts +0 -371
- package/src/proxy/groupStore.ts +0 -336
- package/src/proxy/handler.ts +0 -729
- package/src/proxy/identityProxy.ts +0 -1842
- package/src/proxy/jsonlRecovery.ts +0 -554
- package/src/proxy/logBodyChunks.ts +0 -91
- package/src/proxy/logFinalizer.ts +0 -777
- package/src/proxy/logFinalizer.worker.ts +0 -24
- package/src/proxy/logImportUpload.ts +0 -128
- package/src/proxy/logImporter.ts +0 -813
- package/src/proxy/logIndex.ts +0 -663
- package/src/proxy/logSearch.ts +0 -122
- package/src/proxy/logger.ts +0 -537
- package/src/proxy/openaiOrphanToolStrip.ts +0 -142
- package/src/proxy/platformCommands.ts +0 -258
- package/src/proxy/privateDataPath.ts +0 -419
- package/src/proxy/providerImporters.ts +0 -578
- package/src/proxy/providerScanStore.ts +0 -87
- package/src/proxy/providerSecretStore.ts +0 -216
- package/src/proxy/providers.ts +0 -998
- package/src/proxy/rawStreamCapture.ts +0 -342
- package/src/proxy/runFailures.ts +0 -94
- package/src/proxy/runStore.ts +0 -214
- package/src/proxy/runtimeAdmission.ts +0 -55
- package/src/proxy/runtimeHealth.ts +0 -221
- package/src/proxy/runtimeMetrics.ts +0 -149
- package/src/proxy/runtimeShutdown.ts +0 -157
- package/src/proxy/schemas.ts +0 -112
- package/src/proxy/sessionArchive.ts +0 -479
- package/src/proxy/sessionInfo.ts +0 -266
- package/src/proxy/sessionProcess.ts +0 -194
- package/src/proxy/sessionRuntime.ts +0 -121
- package/src/proxy/sessionSupervisor.ts +0 -305
- package/src/proxy/sessionWorkerEntry.ts +0 -26
- package/src/proxy/shutdownCoordinator.ts +0 -90
- package/src/proxy/socketTracker.ts +0 -639
- package/src/proxy/sqliteLogIndex.ts +0 -733
- package/src/proxy/storageLifecycle.ts +0 -432
- package/src/proxy/store.ts +0 -1773
- package/src/proxy/streamTiming.ts +0 -31
- package/src/proxy/toolSchemaWarnings.ts +0 -529
- package/src/proxy/uiAssetServer.ts +0 -106
- package/src/proxy/upstream.ts +0 -127
- package/src/services/alerts.ts +0 -12
- package/src/services/groups.ts +0 -119
- package/src/services/piAgent.ts +0 -421
- package/src/services/piAgentRetrieval.ts +0 -1180
- package/src/services/result.ts +0 -17
- package/src/services/runs.ts +0 -76
- package/src/ui/bootstrap.ts +0 -167
- package/src/ui/index.html +0 -38
- package/src/ui/logsStreamClient.ts +0 -20
- package/src/ui/main.tsx +0 -13
- package/src/ui/public/runtime-config.js +0 -2
- package/src/ui/router.tsx +0 -13
- package/src/ui/routes/__root.tsx +0 -69
- package/src/ui/routes/index.tsx +0 -35
- package/src/ui/routes/session/$sessionId.tsx +0 -50
- package/src/ui/runtimeDiscovery.ts +0 -50
|
@@ -1,1042 +0,0 @@
|
|
|
1
|
-
import { type JSX, useState, useCallback, useEffect, useMemo } from "react";
|
|
2
|
-
import { Check, Copy, Settings, Terminal } from "lucide-react";
|
|
3
|
-
import { z } from "zod";
|
|
4
|
-
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from "../ui/dialog";
|
|
5
|
-
import { Tabs, TabsList, TabsTrigger, TabsContent } from "../ui/tabs";
|
|
6
|
-
import { Button } from "../ui/button";
|
|
7
|
-
import { INSPECTOR_ICON_TRIGGER_CLASS } from "../ui/icon-trigger";
|
|
8
|
-
import { ProvidersPanel } from "./ProvidersPanel";
|
|
9
|
-
import { useProviders } from "../../lib/useProviders";
|
|
10
|
-
import { useStripConfig } from "../../lib/useStripConfig";
|
|
11
|
-
import { copyTextToClipboard } from "../../lib/clipboard";
|
|
12
|
-
import { fetchJsonWithTimeout } from "../../lib/apiClient";
|
|
13
|
-
import {
|
|
14
|
-
subscribeCodingAgentEndpoints,
|
|
15
|
-
type CodingAgentEndpoints,
|
|
16
|
-
} from "../../lib/codingAgentEndpoints";
|
|
17
|
-
import {
|
|
18
|
-
MAX_PROVIDER_TEST_TIMEOUT_SECONDS,
|
|
19
|
-
MAX_SLOW_RESPONSE_THRESHOLD_SECONDS,
|
|
20
|
-
TimeDisplayFormatSchema,
|
|
21
|
-
type TimeDisplayFormat,
|
|
22
|
-
} from "../../lib/runtimeConfig";
|
|
23
|
-
|
|
24
|
-
export const SETTINGS_SECTIONS = [
|
|
25
|
-
{ value: "providers", label: "Providers" },
|
|
26
|
-
{ value: "proxy", label: "Proxy" },
|
|
27
|
-
{ value: "storage", label: "Storage" },
|
|
28
|
-
{ value: "mcp", label: "MCP" },
|
|
29
|
-
{ value: "onboarding", label: "Onboarding" },
|
|
30
|
-
];
|
|
31
|
-
|
|
32
|
-
export function ResponsiveSettingsTabs(): JSX.Element {
|
|
33
|
-
return (
|
|
34
|
-
<TabsList
|
|
35
|
-
aria-label="Settings sections"
|
|
36
|
-
className="grid w-full grid-cols-3 justify-stretch gap-1 bg-muted/35 p-1 group-data-[orientation=horizontal]/tabs:h-auto sm:grid-cols-5"
|
|
37
|
-
>
|
|
38
|
-
{SETTINGS_SECTIONS.map((section) => (
|
|
39
|
-
<TabsTrigger key={section.value} value={section.value} className="min-w-0 w-full">
|
|
40
|
-
{section.label}
|
|
41
|
-
</TabsTrigger>
|
|
42
|
-
))}
|
|
43
|
-
</TabsList>
|
|
44
|
-
);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export function SettingsDialog(): JSX.Element {
|
|
48
|
-
const [open, setOpen] = useState(false);
|
|
49
|
-
const [activeTab, setActiveTab] = useState("providers");
|
|
50
|
-
const { providers, isLoading, mutate } = useProviders();
|
|
51
|
-
const [testResults, setTestResults] = useState<
|
|
52
|
-
Record<string, import("./ProvidersPanel").TestResults>
|
|
53
|
-
>({});
|
|
54
|
-
const [testingProviders, setTestingProviders] = useState<Set<string>>(new Set());
|
|
55
|
-
const [testingTimeLeft, setTestingTimeLeft] = useState<Record<string, number>>({});
|
|
56
|
-
|
|
57
|
-
const handleTestResultsChange = useCallback(
|
|
58
|
-
(providerId: string, results: import("./ProvidersPanel").TestResults) => {
|
|
59
|
-
setTestResults((prev) => ({ ...prev, [providerId]: results }));
|
|
60
|
-
},
|
|
61
|
-
[],
|
|
62
|
-
);
|
|
63
|
-
|
|
64
|
-
const handleTestingProvidersChange = useCallback((providerId: string, isTesting: boolean) => {
|
|
65
|
-
setTestingProviders((prev) => {
|
|
66
|
-
const next = new Set(prev);
|
|
67
|
-
if (isTesting) {
|
|
68
|
-
next.add(providerId);
|
|
69
|
-
} else {
|
|
70
|
-
next.delete(providerId);
|
|
71
|
-
}
|
|
72
|
-
return next;
|
|
73
|
-
});
|
|
74
|
-
}, []);
|
|
75
|
-
|
|
76
|
-
const handleTestingTimeLeftChange = useCallback(
|
|
77
|
-
(providerId: string, seconds: number | undefined) => {
|
|
78
|
-
setTestingTimeLeft((prev) => {
|
|
79
|
-
if (seconds === undefined) {
|
|
80
|
-
const next = { ...prev };
|
|
81
|
-
delete next[providerId];
|
|
82
|
-
return next;
|
|
83
|
-
}
|
|
84
|
-
return { ...prev, [providerId]: seconds };
|
|
85
|
-
});
|
|
86
|
-
},
|
|
87
|
-
[],
|
|
88
|
-
);
|
|
89
|
-
|
|
90
|
-
return (
|
|
91
|
-
<Dialog open={open} onOpenChange={setOpen}>
|
|
92
|
-
<DialogTrigger asChild>
|
|
93
|
-
<Button
|
|
94
|
-
variant="ghost"
|
|
95
|
-
size="icon"
|
|
96
|
-
className={INSPECTOR_ICON_TRIGGER_CLASS}
|
|
97
|
-
aria-label="Settings"
|
|
98
|
-
title="Settings"
|
|
99
|
-
>
|
|
100
|
-
<Settings className="size-4" />
|
|
101
|
-
<span className="sr-only">Settings</span>
|
|
102
|
-
</Button>
|
|
103
|
-
</DialogTrigger>
|
|
104
|
-
<DialogContent className="flex max-h-[calc(100vh-1rem)] w-[calc(100%-1rem)] max-w-2xl flex-col overflow-hidden p-4 sm:max-h-[80vh] sm:p-6">
|
|
105
|
-
<DialogHeader>
|
|
106
|
-
<DialogTitle>Settings</DialogTitle>
|
|
107
|
-
</DialogHeader>
|
|
108
|
-
|
|
109
|
-
<Tabs
|
|
110
|
-
value={activeTab}
|
|
111
|
-
onValueChange={setActiveTab}
|
|
112
|
-
className="min-h-0 min-w-0 flex-1 overflow-hidden"
|
|
113
|
-
>
|
|
114
|
-
<ResponsiveSettingsTabs />
|
|
115
|
-
|
|
116
|
-
<div className="mt-4 min-w-0 flex-1 overflow-x-hidden overflow-y-auto pr-1 sm:pr-2">
|
|
117
|
-
<TabsContent value="providers">
|
|
118
|
-
<ProvidersPanel
|
|
119
|
-
externalProviders={providers}
|
|
120
|
-
isLoading={isLoading}
|
|
121
|
-
externalTestResults={testResults}
|
|
122
|
-
externalTestingProviders={testingProviders}
|
|
123
|
-
externalTestingTimeLeft={testingTimeLeft}
|
|
124
|
-
onProvidersMutate={() => {
|
|
125
|
-
return mutate();
|
|
126
|
-
}}
|
|
127
|
-
onTestResultsChange={handleTestResultsChange}
|
|
128
|
-
onTestingProvidersChange={handleTestingProvidersChange}
|
|
129
|
-
onTestingTimeLeftChange={handleTestingTimeLeftChange}
|
|
130
|
-
/>
|
|
131
|
-
</TabsContent>
|
|
132
|
-
<TabsContent value="proxy">
|
|
133
|
-
<ProxySettingsTab />
|
|
134
|
-
</TabsContent>
|
|
135
|
-
<TabsContent value="storage">
|
|
136
|
-
<StorageSettingsTab />
|
|
137
|
-
</TabsContent>
|
|
138
|
-
<TabsContent value="mcp">
|
|
139
|
-
<McpSettingsTab />
|
|
140
|
-
</TabsContent>
|
|
141
|
-
<TabsContent value="onboarding">
|
|
142
|
-
<OnboardingSettingsTab />
|
|
143
|
-
</TabsContent>
|
|
144
|
-
</div>
|
|
145
|
-
</Tabs>
|
|
146
|
-
</DialogContent>
|
|
147
|
-
</Dialog>
|
|
148
|
-
);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
type LogStorageStats = {
|
|
152
|
-
memoryCount: number;
|
|
153
|
-
inventory: {
|
|
154
|
-
checkedAt: string;
|
|
155
|
-
totalFiles: number;
|
|
156
|
-
totalBytes: number;
|
|
157
|
-
artifacts: StorageArtifactSummary[];
|
|
158
|
-
};
|
|
159
|
-
policy: {
|
|
160
|
-
maxAgeMs: number;
|
|
161
|
-
maxTotalBytes: number;
|
|
162
|
-
};
|
|
163
|
-
reclaimableBytes: number;
|
|
164
|
-
lastGc: {
|
|
165
|
-
checkedAt: string;
|
|
166
|
-
filesDeleted: number;
|
|
167
|
-
bytesDeleted: number;
|
|
168
|
-
errors: number;
|
|
169
|
-
beforeTotalBytes: number;
|
|
170
|
-
afterTotalBytes: number;
|
|
171
|
-
} | null;
|
|
172
|
-
};
|
|
173
|
-
|
|
174
|
-
type StorageArtifactSummary = {
|
|
175
|
-
kind: string;
|
|
176
|
-
root: string;
|
|
177
|
-
sensitivity: string;
|
|
178
|
-
cleanupBehavior: string;
|
|
179
|
-
fileCount: number;
|
|
180
|
-
bytes: number;
|
|
181
|
-
oldestModifiedAt: string | null;
|
|
182
|
-
newestModifiedAt: string | null;
|
|
183
|
-
};
|
|
184
|
-
|
|
185
|
-
const StorageArtifactSummarySchema = z.object({
|
|
186
|
-
kind: z.string(),
|
|
187
|
-
root: z.string(),
|
|
188
|
-
sensitivity: z.string(),
|
|
189
|
-
cleanupBehavior: z.string(),
|
|
190
|
-
fileCount: z.number(),
|
|
191
|
-
bytes: z.number(),
|
|
192
|
-
oldestModifiedAt: z.string().nullable(),
|
|
193
|
-
newestModifiedAt: z.string().nullable(),
|
|
194
|
-
});
|
|
195
|
-
|
|
196
|
-
const LogStorageStatsSchema = z.object({
|
|
197
|
-
memoryCount: z.number(),
|
|
198
|
-
inventory: z.object({
|
|
199
|
-
checkedAt: z.string(),
|
|
200
|
-
totalFiles: z.number(),
|
|
201
|
-
totalBytes: z.number(),
|
|
202
|
-
artifacts: z.array(StorageArtifactSummarySchema),
|
|
203
|
-
}),
|
|
204
|
-
policy: z.object({
|
|
205
|
-
maxAgeMs: z.number(),
|
|
206
|
-
maxTotalBytes: z.number(),
|
|
207
|
-
}),
|
|
208
|
-
reclaimableBytes: z.number(),
|
|
209
|
-
lastGc: z
|
|
210
|
-
.object({
|
|
211
|
-
checkedAt: z.string(),
|
|
212
|
-
filesDeleted: z.number(),
|
|
213
|
-
bytesDeleted: z.number(),
|
|
214
|
-
errors: z.number(),
|
|
215
|
-
beforeTotalBytes: z.number(),
|
|
216
|
-
afterTotalBytes: z.number(),
|
|
217
|
-
})
|
|
218
|
-
.nullable(),
|
|
219
|
-
});
|
|
220
|
-
|
|
221
|
-
const STORAGE_STATS_FETCH_TIMEOUT_MS = 10_000;
|
|
222
|
-
|
|
223
|
-
function formatBytes(bytes: number): string {
|
|
224
|
-
if (bytes < 1024) return `${bytes} B`;
|
|
225
|
-
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KiB`;
|
|
226
|
-
if (bytes < 1024 * 1024 * 1024) return `${(bytes / 1024 / 1024).toFixed(1)} MiB`;
|
|
227
|
-
return `${(bytes / 1024 / 1024 / 1024).toFixed(1)} GiB`;
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
function formatRetention(maxAgeMs: number): string {
|
|
231
|
-
const days = Math.round(maxAgeMs / 1000 / 60 / 60 / 24);
|
|
232
|
-
return `${days.toLocaleString()} days`;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
function StorageSettingsTab(): JSX.Element {
|
|
236
|
-
const [stats, setStats] = useState<LogStorageStats | null>(null);
|
|
237
|
-
const [error, setError] = useState<string | null>(null);
|
|
238
|
-
const [loading, setLoading] = useState(false);
|
|
239
|
-
const [gcLoading, setGcLoading] = useState(false);
|
|
240
|
-
const [copiedId, setCopiedId] = useState<string | null>(null);
|
|
241
|
-
|
|
242
|
-
const refresh = useCallback(async () => {
|
|
243
|
-
setLoading(true);
|
|
244
|
-
setError(null);
|
|
245
|
-
try {
|
|
246
|
-
const data = await fetchJsonWithTimeout(
|
|
247
|
-
"/api/storage",
|
|
248
|
-
LogStorageStatsSchema,
|
|
249
|
-
STORAGE_STATS_FETCH_TIMEOUT_MS,
|
|
250
|
-
undefined,
|
|
251
|
-
(response) => `Failed to load storage stats: HTTP ${String(response.status)}`,
|
|
252
|
-
);
|
|
253
|
-
setStats(data);
|
|
254
|
-
} catch (err) {
|
|
255
|
-
setError(err instanceof Error ? err.message : String(err));
|
|
256
|
-
} finally {
|
|
257
|
-
setLoading(false);
|
|
258
|
-
}
|
|
259
|
-
}, []);
|
|
260
|
-
|
|
261
|
-
useEffect(() => {
|
|
262
|
-
void refresh();
|
|
263
|
-
}, [refresh]);
|
|
264
|
-
|
|
265
|
-
const handleCopy = useCallback((id: string, value: string) => {
|
|
266
|
-
void copyTextToClipboard(value).then((success) => {
|
|
267
|
-
if (!success) return;
|
|
268
|
-
setCopiedId(id);
|
|
269
|
-
setTimeout(() => setCopiedId(null), 1600);
|
|
270
|
-
});
|
|
271
|
-
}, []);
|
|
272
|
-
|
|
273
|
-
const handleRunGc = useCallback(async () => {
|
|
274
|
-
setGcLoading(true);
|
|
275
|
-
setError(null);
|
|
276
|
-
try {
|
|
277
|
-
const data = await fetchJsonWithTimeout(
|
|
278
|
-
"/api/storage",
|
|
279
|
-
LogStorageStatsSchema,
|
|
280
|
-
STORAGE_STATS_FETCH_TIMEOUT_MS,
|
|
281
|
-
{ method: "POST" },
|
|
282
|
-
(response) => `Failed to run storage GC: HTTP ${String(response.status)}`,
|
|
283
|
-
);
|
|
284
|
-
setStats(data);
|
|
285
|
-
} catch (err) {
|
|
286
|
-
setError(err instanceof Error ? err.message : String(err));
|
|
287
|
-
} finally {
|
|
288
|
-
setGcLoading(false);
|
|
289
|
-
}
|
|
290
|
-
}, []);
|
|
291
|
-
|
|
292
|
-
return (
|
|
293
|
-
<div className="space-y-4">
|
|
294
|
-
<div className="flex items-center justify-between gap-3">
|
|
295
|
-
<div className="min-w-0">
|
|
296
|
-
<h3 className="text-sm font-semibold">Storage lifecycle</h3>
|
|
297
|
-
<p className="text-xs text-muted-foreground">
|
|
298
|
-
Inspect local captured-data footprint, retention policy, and safe reclaim actions.
|
|
299
|
-
</p>
|
|
300
|
-
</div>
|
|
301
|
-
<div className="flex shrink-0 items-center gap-2">
|
|
302
|
-
<Button
|
|
303
|
-
type="button"
|
|
304
|
-
variant="outline"
|
|
305
|
-
size="sm"
|
|
306
|
-
onClick={() => void handleRunGc()}
|
|
307
|
-
disabled={gcLoading}
|
|
308
|
-
>
|
|
309
|
-
{gcLoading ? "Running..." : "Run GC now"}
|
|
310
|
-
</Button>
|
|
311
|
-
<Button type="button" variant="outline" size="sm" onClick={() => void refresh()}>
|
|
312
|
-
{loading ? "Refreshing..." : "Refresh"}
|
|
313
|
-
</Button>
|
|
314
|
-
</div>
|
|
315
|
-
</div>
|
|
316
|
-
|
|
317
|
-
{stats !== null && (
|
|
318
|
-
<div className="grid gap-2 text-xs">
|
|
319
|
-
<div className="grid gap-2 sm:grid-cols-2">
|
|
320
|
-
<StorageMetricCard
|
|
321
|
-
label="Persisted footprint"
|
|
322
|
-
value={`${stats.inventory.totalFiles.toLocaleString()} files / ${formatBytes(
|
|
323
|
-
stats.inventory.totalBytes,
|
|
324
|
-
)}`}
|
|
325
|
-
detail={`Checked ${new Date(stats.inventory.checkedAt).toLocaleString()}`}
|
|
326
|
-
/>
|
|
327
|
-
<StorageMetricCard
|
|
328
|
-
label="Auto-reclaimable"
|
|
329
|
-
value={formatBytes(stats.reclaimableBytes)}
|
|
330
|
-
detail={`Retention ${formatRetention(stats.policy.maxAgeMs)} / max ${formatBytes(
|
|
331
|
-
stats.policy.maxTotalBytes,
|
|
332
|
-
)}`}
|
|
333
|
-
/>
|
|
334
|
-
<StorageMetricCard
|
|
335
|
-
label="In-memory logs"
|
|
336
|
-
value={`${stats.memoryCount.toLocaleString()} loaded`}
|
|
337
|
-
detail="Recent completed entries kept hot for the UI"
|
|
338
|
-
/>
|
|
339
|
-
<StorageMetricCard
|
|
340
|
-
label="Last GC"
|
|
341
|
-
value={
|
|
342
|
-
stats.lastGc === null
|
|
343
|
-
? "Not run yet"
|
|
344
|
-
: `${stats.lastGc.filesDeleted.toLocaleString()} files / ${formatBytes(
|
|
345
|
-
stats.lastGc.bytesDeleted,
|
|
346
|
-
)}`
|
|
347
|
-
}
|
|
348
|
-
detail={
|
|
349
|
-
stats.lastGc === null
|
|
350
|
-
? "Runs at startup, on schedule, or manually here"
|
|
351
|
-
: `${new Date(stats.lastGc.checkedAt).toLocaleString()} · ${
|
|
352
|
-
stats.lastGc.errors
|
|
353
|
-
} errors`
|
|
354
|
-
}
|
|
355
|
-
/>
|
|
356
|
-
</div>
|
|
357
|
-
{stats.inventory.artifacts.map((artifact) => (
|
|
358
|
-
<StorageArtifactRow
|
|
359
|
-
key={`${artifact.kind}:${artifact.root}`}
|
|
360
|
-
artifact={artifact}
|
|
361
|
-
copiedId={copiedId}
|
|
362
|
-
onCopy={handleCopy}
|
|
363
|
-
/>
|
|
364
|
-
))}
|
|
365
|
-
</div>
|
|
366
|
-
)}
|
|
367
|
-
|
|
368
|
-
{error !== null && <p className="text-xs text-destructive">{error}</p>}
|
|
369
|
-
</div>
|
|
370
|
-
);
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
function cleanupBehaviorLabel(cleanupBehavior: string): string {
|
|
374
|
-
switch (cleanupBehavior) {
|
|
375
|
-
case "retention-gc":
|
|
376
|
-
return "Retention GC";
|
|
377
|
-
case "orphan-reclaim":
|
|
378
|
-
return "Orphan reclaim";
|
|
379
|
-
case "rotation":
|
|
380
|
-
return "Rotation-owned";
|
|
381
|
-
case "manual-owner-delete":
|
|
382
|
-
return "Manual only";
|
|
383
|
-
default:
|
|
384
|
-
return cleanupBehavior;
|
|
385
|
-
}
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
function StorageMetricCard({
|
|
389
|
-
label,
|
|
390
|
-
value,
|
|
391
|
-
detail,
|
|
392
|
-
}: {
|
|
393
|
-
label: string;
|
|
394
|
-
value: string;
|
|
395
|
-
detail: string;
|
|
396
|
-
}): JSX.Element {
|
|
397
|
-
return (
|
|
398
|
-
<div className="rounded-md bg-muted/20 px-3 py-2">
|
|
399
|
-
<div className="font-medium">{label}</div>
|
|
400
|
-
<div className="mt-1 font-mono text-muted-foreground">{value}</div>
|
|
401
|
-
<div className="mt-1 text-[11px] text-muted-foreground">{detail}</div>
|
|
402
|
-
</div>
|
|
403
|
-
);
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
function StorageArtifactRow({
|
|
407
|
-
artifact,
|
|
408
|
-
copiedId,
|
|
409
|
-
onCopy,
|
|
410
|
-
}: {
|
|
411
|
-
artifact: StorageArtifactSummary;
|
|
412
|
-
copiedId: string | null;
|
|
413
|
-
onCopy: (id: string, value: string) => void;
|
|
414
|
-
}): JSX.Element {
|
|
415
|
-
const id = `storage-${artifact.kind}`;
|
|
416
|
-
const oldest = artifact.oldestModifiedAt === null ? "none" : new Date(artifact.oldestModifiedAt);
|
|
417
|
-
const newest = artifact.newestModifiedAt === null ? "none" : new Date(artifact.newestModifiedAt);
|
|
418
|
-
return (
|
|
419
|
-
<div className="rounded-md border border-border/45 bg-muted/15 px-3 py-2">
|
|
420
|
-
<div className="flex flex-wrap items-center justify-between gap-2">
|
|
421
|
-
<div>
|
|
422
|
-
<div className="font-medium">{artifact.kind}</div>
|
|
423
|
-
<div className="mt-1 text-[11px] text-muted-foreground">
|
|
424
|
-
{cleanupBehaviorLabel(artifact.cleanupBehavior)} · {artifact.sensitivity}
|
|
425
|
-
</div>
|
|
426
|
-
</div>
|
|
427
|
-
<div className="text-right font-mono text-muted-foreground">
|
|
428
|
-
{artifact.fileCount.toLocaleString()} files / {formatBytes(artifact.bytes)}
|
|
429
|
-
</div>
|
|
430
|
-
</div>
|
|
431
|
-
<div className="mt-2 grid gap-1 text-[11px] text-muted-foreground sm:grid-cols-2">
|
|
432
|
-
<div>Oldest: {oldest instanceof Date ? oldest.toLocaleString() : oldest}</div>
|
|
433
|
-
<div>Newest: {newest instanceof Date ? newest.toLocaleString() : newest}</div>
|
|
434
|
-
</div>
|
|
435
|
-
<div className="mt-2">
|
|
436
|
-
<CopyableSetupValue
|
|
437
|
-
id={id}
|
|
438
|
-
label="Root path"
|
|
439
|
-
value={artifact.root}
|
|
440
|
-
copiedId={copiedId}
|
|
441
|
-
onCopy={onCopy}
|
|
442
|
-
/>
|
|
443
|
-
</div>
|
|
444
|
-
</div>
|
|
445
|
-
);
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
function CopyableSetupValue({
|
|
449
|
-
id,
|
|
450
|
-
label,
|
|
451
|
-
value,
|
|
452
|
-
copiedId,
|
|
453
|
-
onCopy,
|
|
454
|
-
}: {
|
|
455
|
-
id: string;
|
|
456
|
-
label: string;
|
|
457
|
-
value: string;
|
|
458
|
-
copiedId: string | null;
|
|
459
|
-
onCopy: (id: string, value: string) => void;
|
|
460
|
-
}): JSX.Element {
|
|
461
|
-
const copied = copiedId === id;
|
|
462
|
-
return (
|
|
463
|
-
<div className="min-w-0 rounded-md border border-border/45 bg-muted/15 px-3 py-2 transition-colors hover:bg-muted/25">
|
|
464
|
-
<div className="mb-1 text-xs font-medium text-muted-foreground">{label}</div>
|
|
465
|
-
<div className="flex min-w-0 items-center gap-2">
|
|
466
|
-
<code className="min-w-0 flex-1 truncate font-mono text-xs text-foreground" title={value}>
|
|
467
|
-
{value}
|
|
468
|
-
</code>
|
|
469
|
-
<Button
|
|
470
|
-
type="button"
|
|
471
|
-
variant="ghost"
|
|
472
|
-
size="icon"
|
|
473
|
-
className="size-7 shrink-0"
|
|
474
|
-
onClick={() => onCopy(id, value)}
|
|
475
|
-
aria-label={copied ? `Copied ${label}` : `Copy ${label}`}
|
|
476
|
-
>
|
|
477
|
-
{copied ? (
|
|
478
|
-
<Check className="size-3.5 text-status-success" />
|
|
479
|
-
) : (
|
|
480
|
-
<Copy className="size-3.5" />
|
|
481
|
-
)}
|
|
482
|
-
</Button>
|
|
483
|
-
</div>
|
|
484
|
-
</div>
|
|
485
|
-
);
|
|
486
|
-
}
|
|
487
|
-
|
|
488
|
-
export function OnboardingSettingsTab(): JSX.Element {
|
|
489
|
-
const [copiedId, setCopiedId] = useState<string | null>(null);
|
|
490
|
-
const [endpoints, setEndpoints] = useState<CodingAgentEndpoints | null>(null);
|
|
491
|
-
useEffect(() => subscribeCodingAgentEndpoints(setEndpoints), []);
|
|
492
|
-
const values = useMemo(
|
|
493
|
-
() => [
|
|
494
|
-
{ id: "status", label: "Check onboarding", value: "agent-inspector onboard --status" },
|
|
495
|
-
{
|
|
496
|
-
id: "status-json",
|
|
497
|
-
label: "Check onboarding JSON",
|
|
498
|
-
value: "agent-inspector onboard --status --json",
|
|
499
|
-
},
|
|
500
|
-
{ id: "refresh", label: "Refresh generated files", value: "agent-inspector onboard --force" },
|
|
501
|
-
{
|
|
502
|
-
id: "uninstall",
|
|
503
|
-
label: "Remove matching generated files",
|
|
504
|
-
value: "agent-inspector onboard --uninstall",
|
|
505
|
-
},
|
|
506
|
-
{ id: "claude", label: "Claude Code command", value: "/agent-inspector:onboard" },
|
|
507
|
-
{ id: "doctor", label: "Backend doctor", value: "agent-inspector doctor --verbose" },
|
|
508
|
-
{
|
|
509
|
-
id: "support-bundle",
|
|
510
|
-
label: "Redacted support bundle",
|
|
511
|
-
value: "agent-inspector doctor --support-bundle",
|
|
512
|
-
},
|
|
513
|
-
{
|
|
514
|
-
id: "codex",
|
|
515
|
-
label: "Codex prompt",
|
|
516
|
-
value: "Use the agent-inspector-onboard skill",
|
|
517
|
-
},
|
|
518
|
-
{
|
|
519
|
-
id: "opencode-config",
|
|
520
|
-
label: "OpenCode config",
|
|
521
|
-
value: "agent-inspector onboard --opencode-only",
|
|
522
|
-
},
|
|
523
|
-
{
|
|
524
|
-
id: "opencode-status",
|
|
525
|
-
label: "OpenCode status",
|
|
526
|
-
value: "agent-inspector onboard --status --opencode-only",
|
|
527
|
-
},
|
|
528
|
-
{ id: "opencode-verify", label: "OpenCode verify", value: "opencode mcp list" },
|
|
529
|
-
{
|
|
530
|
-
id: "mimo-config",
|
|
531
|
-
label: "MiMo Code config",
|
|
532
|
-
value: "agent-inspector onboard --mimo-only",
|
|
533
|
-
},
|
|
534
|
-
{
|
|
535
|
-
id: "mimo-status",
|
|
536
|
-
label: "MiMo Code status",
|
|
537
|
-
value: "agent-inspector onboard --status --mimo-only",
|
|
538
|
-
},
|
|
539
|
-
{ id: "mimo-verify", label: "MiMo Code verify", value: "mimo mcp list" },
|
|
540
|
-
...(endpoints === null
|
|
541
|
-
? []
|
|
542
|
-
: [
|
|
543
|
-
{
|
|
544
|
-
id: "opencode-proxy",
|
|
545
|
-
label: "OpenCode proxy",
|
|
546
|
-
value: `LLM_BASE_URL=${endpoints.proxy}`,
|
|
547
|
-
},
|
|
548
|
-
{
|
|
549
|
-
id: "mimo-proxy",
|
|
550
|
-
label: "MiMo Code proxy",
|
|
551
|
-
value: `OPENAI_BASE_URL=${endpoints.openAiV1}`,
|
|
552
|
-
},
|
|
553
|
-
{ id: "mcp", label: "MCP URL", value: endpoints.mcp },
|
|
554
|
-
{ id: "proxy", label: "Proxy URL", value: endpoints.proxy },
|
|
555
|
-
{
|
|
556
|
-
id: "anthropic",
|
|
557
|
-
label: "Anthropic base",
|
|
558
|
-
value: `ANTHROPIC_BASE_URL=${endpoints.proxy}`,
|
|
559
|
-
},
|
|
560
|
-
{
|
|
561
|
-
id: "openai",
|
|
562
|
-
label: "OpenAI base",
|
|
563
|
-
value: `OPENAI_BASE_URL=${endpoints.openAiV1}`,
|
|
564
|
-
},
|
|
565
|
-
]),
|
|
566
|
-
],
|
|
567
|
-
[endpoints],
|
|
568
|
-
);
|
|
569
|
-
|
|
570
|
-
const handleCopy = useCallback((id: string, value: string) => {
|
|
571
|
-
void copyTextToClipboard(value).then((success) => {
|
|
572
|
-
if (!success) return;
|
|
573
|
-
setCopiedId(id);
|
|
574
|
-
setTimeout(() => setCopiedId(null), 1600);
|
|
575
|
-
});
|
|
576
|
-
}, []);
|
|
577
|
-
|
|
578
|
-
return (
|
|
579
|
-
<div className="min-w-0 space-y-4">
|
|
580
|
-
<div className="flex items-center gap-2">
|
|
581
|
-
<Terminal className="size-4 text-muted-foreground" />
|
|
582
|
-
<h3 className="text-sm font-semibold">Agent onboarding</h3>
|
|
583
|
-
</div>
|
|
584
|
-
<div className="grid gap-2">
|
|
585
|
-
{values.map((item) => (
|
|
586
|
-
<CopyableSetupValue
|
|
587
|
-
key={item.id}
|
|
588
|
-
id={item.id}
|
|
589
|
-
label={item.label}
|
|
590
|
-
value={item.value}
|
|
591
|
-
copiedId={copiedId}
|
|
592
|
-
onCopy={handleCopy}
|
|
593
|
-
/>
|
|
594
|
-
))}
|
|
595
|
-
</div>
|
|
596
|
-
<div className="grid gap-2 rounded-md border border-status-info/25 bg-status-info/10 px-3 py-2 text-xs">
|
|
597
|
-
<div className="font-medium text-foreground">Verified first trace flow</div>
|
|
598
|
-
<ol className="ml-4 list-decimal space-y-1 text-muted-foreground">
|
|
599
|
-
<li>Start Agent Inspector and confirm the application bar shows Live.</li>
|
|
600
|
-
<li>Copy the Proxy URL or MCP URL that matches your coding agent.</li>
|
|
601
|
-
<li>Run a tiny coding-agent prompt such as “say hello and stop”.</li>
|
|
602
|
-
<li>
|
|
603
|
-
Return to Logs and confirm one new request appears with request, response, tokens, and
|
|
604
|
-
tool activity when present.
|
|
605
|
-
</li>
|
|
606
|
-
</ol>
|
|
607
|
-
</div>
|
|
608
|
-
<div className="grid gap-2 rounded-md bg-muted/15 px-3 py-2 text-xs text-muted-foreground">
|
|
609
|
-
<div className="flex items-center gap-2">
|
|
610
|
-
<Check className="size-3.5 text-status-success" />
|
|
611
|
-
<span>Provider test creates a traceable memory probe session.</span>
|
|
612
|
-
</div>
|
|
613
|
-
<div className="flex items-center gap-2">
|
|
614
|
-
<Check className="size-3.5 text-status-success" />
|
|
615
|
-
<span>Captured sessions can produce reviewable memory candidates.</span>
|
|
616
|
-
</div>
|
|
617
|
-
<div className="flex items-start gap-2">
|
|
618
|
-
<Check className="mt-0.5 size-3.5 text-status-success" />
|
|
619
|
-
<span>
|
|
620
|
-
Streamable HTTP clients should use the MCP URL directly. Stdio-only clients should use
|
|
621
|
-
<code className="mx-1 rounded bg-muted px-1 py-0.5 font-mono text-[11px] text-foreground">
|
|
622
|
-
agent-inspector-mcp stdio
|
|
623
|
-
</code>
|
|
624
|
-
instead. Configure only one entry for the same Inspector.
|
|
625
|
-
</span>
|
|
626
|
-
</div>
|
|
627
|
-
<div className="flex items-start gap-2">
|
|
628
|
-
<Check className="mt-0.5 size-3.5 text-status-success" />
|
|
629
|
-
<span>
|
|
630
|
-
OpenCode onboarding safely merges{" "}
|
|
631
|
-
<code className="rounded bg-muted px-1 py-0.5 font-mono text-[11px] text-foreground">
|
|
632
|
-
mcp.agent-inspector
|
|
633
|
-
</code>{" "}
|
|
634
|
-
into{" "}
|
|
635
|
-
<code className="rounded bg-muted px-1 py-0.5 font-mono text-[11px] text-foreground">
|
|
636
|
-
opencode.json
|
|
637
|
-
</code>
|
|
638
|
-
, then verify with{" "}
|
|
639
|
-
<code className="rounded bg-muted px-1 py-0.5 font-mono text-[11px] text-foreground">
|
|
640
|
-
opencode mcp list
|
|
641
|
-
</code>
|
|
642
|
-
.
|
|
643
|
-
</span>
|
|
644
|
-
</div>
|
|
645
|
-
<div className="flex items-start gap-2">
|
|
646
|
-
<Check className="mt-0.5 size-3.5 text-status-success" />
|
|
647
|
-
<span>
|
|
648
|
-
MiMo Code onboarding safely merges{" "}
|
|
649
|
-
<code className="rounded bg-muted px-1 py-0.5 font-mono text-[11px] text-foreground">
|
|
650
|
-
mcp.agent-inspector
|
|
651
|
-
</code>{" "}
|
|
652
|
-
into{" "}
|
|
653
|
-
<code className="rounded bg-muted px-1 py-0.5 font-mono text-[11px] text-foreground">
|
|
654
|
-
mimocode.jsonc
|
|
655
|
-
</code>
|
|
656
|
-
, then route OpenAI-format traffic with{" "}
|
|
657
|
-
<code className="rounded bg-muted px-1 py-0.5 font-mono text-[11px] text-foreground">
|
|
658
|
-
OPENAI_BASE_URL
|
|
659
|
-
</code>
|
|
660
|
-
.
|
|
661
|
-
</span>
|
|
662
|
-
</div>
|
|
663
|
-
<div className="flex items-start gap-2">
|
|
664
|
-
<Check className="mt-0.5 size-3.5 text-status-success" />
|
|
665
|
-
<span>
|
|
666
|
-
If your AI tool runs in another container or host, replace localhost with an address
|
|
667
|
-
reachable from that tool and verify the network/firewall path.
|
|
668
|
-
</span>
|
|
669
|
-
</div>
|
|
670
|
-
<div className="flex items-start gap-2">
|
|
671
|
-
<Check className="mt-0.5 size-3.5 text-status-success" />
|
|
672
|
-
<span>
|
|
673
|
-
If the first trace does not appear, run{" "}
|
|
674
|
-
<code className="rounded bg-muted px-1 py-0.5 font-mono text-[11px] text-foreground">
|
|
675
|
-
agent-inspector doctor --verbose
|
|
676
|
-
</code>{" "}
|
|
677
|
-
and compare the agent base URL with the current Proxy URL. A base-path mismatch such as{" "}
|
|
678
|
-
<code className="rounded bg-muted px-1 py-0.5 font-mono text-[11px] text-foreground">
|
|
679
|
-
/
|
|
680
|
-
</code>{" "}
|
|
681
|
-
versus{" "}
|
|
682
|
-
<code className="rounded bg-muted px-1 py-0.5 font-mono text-[11px] text-foreground">
|
|
683
|
-
/inspector
|
|
684
|
-
</code>{" "}
|
|
685
|
-
means the tool is talking to a different Inspector surface.
|
|
686
|
-
</span>
|
|
687
|
-
</div>
|
|
688
|
-
</div>
|
|
689
|
-
</div>
|
|
690
|
-
);
|
|
691
|
-
}
|
|
692
|
-
|
|
693
|
-
function McpSettingsTab(): JSX.Element {
|
|
694
|
-
const [copiedId, setCopiedId] = useState<string | null>(null);
|
|
695
|
-
const [endpoint, setEndpoint] = useState<string | null>(null);
|
|
696
|
-
useEffect(
|
|
697
|
-
() =>
|
|
698
|
-
subscribeCodingAgentEndpoints((endpoints) => {
|
|
699
|
-
setEndpoint(endpoints?.mcp ?? null);
|
|
700
|
-
}),
|
|
701
|
-
[],
|
|
702
|
-
);
|
|
703
|
-
const values = useMemo(
|
|
704
|
-
() =>
|
|
705
|
-
endpoint === null
|
|
706
|
-
? []
|
|
707
|
-
: [
|
|
708
|
-
{ id: "mcp-url", label: "Streamable HTTP MCP URL", value: endpoint },
|
|
709
|
-
{
|
|
710
|
-
id: "stdio",
|
|
711
|
-
label: "Stdio bridge command",
|
|
712
|
-
value: `agent-inspector-mcp stdio --url ${endpoint}`,
|
|
713
|
-
},
|
|
714
|
-
{
|
|
715
|
-
id: "doctor",
|
|
716
|
-
label: "Bridge doctor",
|
|
717
|
-
value: `agent-inspector-mcp doctor --url ${endpoint}`,
|
|
718
|
-
},
|
|
719
|
-
{
|
|
720
|
-
id: "writes",
|
|
721
|
-
label: "Enable write tools",
|
|
722
|
-
value: "AGENT_INSPECTOR_MCP_WRITES=1 agent-inspector",
|
|
723
|
-
},
|
|
724
|
-
{
|
|
725
|
-
id: "capabilities",
|
|
726
|
-
label: "Capabilities resource",
|
|
727
|
-
value: "inspector://mcp/capabilities",
|
|
728
|
-
},
|
|
729
|
-
{
|
|
730
|
-
id: "context",
|
|
731
|
-
label: "Current context resource",
|
|
732
|
-
value: "inspector://context/current",
|
|
733
|
-
},
|
|
734
|
-
{
|
|
735
|
-
id: "streamable-json",
|
|
736
|
-
label: "Streamable HTTP JSON",
|
|
737
|
-
value: JSON.stringify(
|
|
738
|
-
{
|
|
739
|
-
mcpServers: {
|
|
740
|
-
"agent-inspector": {
|
|
741
|
-
type: "streamableHttp",
|
|
742
|
-
url: endpoint,
|
|
743
|
-
},
|
|
744
|
-
},
|
|
745
|
-
},
|
|
746
|
-
null,
|
|
747
|
-
2,
|
|
748
|
-
),
|
|
749
|
-
},
|
|
750
|
-
{
|
|
751
|
-
id: "stdio-json",
|
|
752
|
-
label: "Stdio MCP JSON",
|
|
753
|
-
value: JSON.stringify(
|
|
754
|
-
{
|
|
755
|
-
mcpServers: {
|
|
756
|
-
"agent-inspector": {
|
|
757
|
-
command: "agent-inspector-mcp",
|
|
758
|
-
args: ["stdio", "--url", endpoint],
|
|
759
|
-
},
|
|
760
|
-
},
|
|
761
|
-
},
|
|
762
|
-
null,
|
|
763
|
-
2,
|
|
764
|
-
),
|
|
765
|
-
},
|
|
766
|
-
{
|
|
767
|
-
id: "opencode-local",
|
|
768
|
-
label: "OpenCode local MCP",
|
|
769
|
-
value: JSON.stringify(
|
|
770
|
-
{
|
|
771
|
-
mcp: {
|
|
772
|
-
"agent-inspector": {
|
|
773
|
-
type: "local",
|
|
774
|
-
command: ["agent-inspector-mcp", "stdio", "--url", endpoint],
|
|
775
|
-
enabled: true,
|
|
776
|
-
},
|
|
777
|
-
},
|
|
778
|
-
},
|
|
779
|
-
null,
|
|
780
|
-
2,
|
|
781
|
-
),
|
|
782
|
-
},
|
|
783
|
-
{
|
|
784
|
-
id: "mimo-local",
|
|
785
|
-
label: "MiMo Code local MCP",
|
|
786
|
-
value: JSON.stringify(
|
|
787
|
-
{
|
|
788
|
-
mcp: {
|
|
789
|
-
"agent-inspector": {
|
|
790
|
-
type: "local",
|
|
791
|
-
command: ["agent-inspector-mcp", "stdio", "--url", endpoint],
|
|
792
|
-
enabled: true,
|
|
793
|
-
},
|
|
794
|
-
},
|
|
795
|
-
},
|
|
796
|
-
null,
|
|
797
|
-
2,
|
|
798
|
-
),
|
|
799
|
-
},
|
|
800
|
-
{
|
|
801
|
-
id: "codex-toml",
|
|
802
|
-
label: "Codex TOML",
|
|
803
|
-
value: `[mcp_servers.agent-inspector]\ncommand = "agent-inspector-mcp"\nargs = ["stdio", "--url", "${endpoint}"]`,
|
|
804
|
-
},
|
|
805
|
-
],
|
|
806
|
-
[endpoint],
|
|
807
|
-
);
|
|
808
|
-
|
|
809
|
-
const handleCopy = useCallback((id: string, value: string) => {
|
|
810
|
-
void copyTextToClipboard(value).then((success) => {
|
|
811
|
-
if (!success) return;
|
|
812
|
-
setCopiedId(id);
|
|
813
|
-
setTimeout(() => setCopiedId(null), 1600);
|
|
814
|
-
});
|
|
815
|
-
}, []);
|
|
816
|
-
|
|
817
|
-
return (
|
|
818
|
-
<div className="min-w-0 space-y-4">
|
|
819
|
-
<div className="flex items-center gap-2">
|
|
820
|
-
<Terminal className="size-4 text-muted-foreground" />
|
|
821
|
-
<h3 className="text-sm font-semibold">MCP access</h3>
|
|
822
|
-
</div>
|
|
823
|
-
<div className="grid gap-2 rounded-md bg-muted/15 px-3 py-2 text-xs text-muted-foreground">
|
|
824
|
-
<div>
|
|
825
|
-
Use Streamable HTTP when the client supports URL-based MCP. Use the stdio bridge only for
|
|
826
|
-
stdio-only clients. Configure one entry for the same Inspector instance.
|
|
827
|
-
</div>
|
|
828
|
-
<div>
|
|
829
|
-
If the MCP client runs in another container or host, replace localhost with a reachable
|
|
830
|
-
host/IP and verify the network path.
|
|
831
|
-
</div>
|
|
832
|
-
</div>
|
|
833
|
-
{endpoint === null ? (
|
|
834
|
-
<div
|
|
835
|
-
role="alert"
|
|
836
|
-
className="rounded-md bg-destructive/10 px-3 py-2 text-xs text-destructive"
|
|
837
|
-
>
|
|
838
|
-
The browser runtime does not provide a valid agent-facing MCP endpoint.
|
|
839
|
-
</div>
|
|
840
|
-
) : (
|
|
841
|
-
<div className="grid gap-2">
|
|
842
|
-
{values.map((item) => (
|
|
843
|
-
<CopyableSetupValue
|
|
844
|
-
key={item.id}
|
|
845
|
-
id={item.id}
|
|
846
|
-
label={item.label}
|
|
847
|
-
value={item.value}
|
|
848
|
-
copiedId={copiedId}
|
|
849
|
-
onCopy={handleCopy}
|
|
850
|
-
/>
|
|
851
|
-
))}
|
|
852
|
-
</div>
|
|
853
|
-
)}
|
|
854
|
-
</div>
|
|
855
|
-
);
|
|
856
|
-
}
|
|
857
|
-
|
|
858
|
-
function ProxySettingsTab(): JSX.Element {
|
|
859
|
-
const {
|
|
860
|
-
strip,
|
|
861
|
-
slowResponseThresholdSeconds,
|
|
862
|
-
providerTestTimeoutSeconds,
|
|
863
|
-
timeDisplayFormat,
|
|
864
|
-
isLoading,
|
|
865
|
-
setStrip,
|
|
866
|
-
setSlowResponseThresholdSeconds,
|
|
867
|
-
setProviderTestTimeoutSeconds,
|
|
868
|
-
setTimeDisplayFormat,
|
|
869
|
-
} = useStripConfig();
|
|
870
|
-
const [error, setError] = useState<string | null>(null);
|
|
871
|
-
const [pending, setPending] = useState(false);
|
|
872
|
-
|
|
873
|
-
const handleToggle = useCallback(
|
|
874
|
-
async (next: boolean) => {
|
|
875
|
-
setError(null);
|
|
876
|
-
setPending(true);
|
|
877
|
-
try {
|
|
878
|
-
await setStrip(next);
|
|
879
|
-
} catch (err) {
|
|
880
|
-
setError(err instanceof Error ? err.message : String(err));
|
|
881
|
-
} finally {
|
|
882
|
-
setPending(false);
|
|
883
|
-
}
|
|
884
|
-
},
|
|
885
|
-
[setStrip],
|
|
886
|
-
);
|
|
887
|
-
|
|
888
|
-
const handleThresholdChange = useCallback(
|
|
889
|
-
async (next: number) => {
|
|
890
|
-
setError(null);
|
|
891
|
-
setPending(true);
|
|
892
|
-
try {
|
|
893
|
-
await setSlowResponseThresholdSeconds(next);
|
|
894
|
-
} catch (err) {
|
|
895
|
-
setError(err instanceof Error ? err.message : String(err));
|
|
896
|
-
} finally {
|
|
897
|
-
setPending(false);
|
|
898
|
-
}
|
|
899
|
-
},
|
|
900
|
-
[setSlowResponseThresholdSeconds],
|
|
901
|
-
);
|
|
902
|
-
|
|
903
|
-
const handleProviderTestTimeoutChange = useCallback(
|
|
904
|
-
async (next: number) => {
|
|
905
|
-
setError(null);
|
|
906
|
-
setPending(true);
|
|
907
|
-
try {
|
|
908
|
-
await setProviderTestTimeoutSeconds(next);
|
|
909
|
-
} catch (err) {
|
|
910
|
-
setError(err instanceof Error ? err.message : String(err));
|
|
911
|
-
} finally {
|
|
912
|
-
setPending(false);
|
|
913
|
-
}
|
|
914
|
-
},
|
|
915
|
-
[setProviderTestTimeoutSeconds],
|
|
916
|
-
);
|
|
917
|
-
|
|
918
|
-
const handleTimeDisplayFormatChange = useCallback(
|
|
919
|
-
async (next: TimeDisplayFormat) => {
|
|
920
|
-
setError(null);
|
|
921
|
-
setPending(true);
|
|
922
|
-
try {
|
|
923
|
-
await setTimeDisplayFormat(next);
|
|
924
|
-
} catch (err) {
|
|
925
|
-
setError(err instanceof Error ? err.message : String(err));
|
|
926
|
-
} finally {
|
|
927
|
-
setPending(false);
|
|
928
|
-
}
|
|
929
|
-
},
|
|
930
|
-
[setTimeDisplayFormat],
|
|
931
|
-
);
|
|
932
|
-
|
|
933
|
-
return (
|
|
934
|
-
<div className="space-y-4">
|
|
935
|
-
<div className="space-y-1">
|
|
936
|
-
<h3 className="text-sm font-semibold">Claude Code billing header</h3>
|
|
937
|
-
<p className="text-xs text-muted-foreground">
|
|
938
|
-
Strip Claude Code's synthetic billing block before upstream forwarding. This can improve
|
|
939
|
-
prefix-cache hits with third-party providers and is persisted to <code>config.json</code>.
|
|
940
|
-
</p>
|
|
941
|
-
</div>
|
|
942
|
-
|
|
943
|
-
<label className="flex items-center gap-3">
|
|
944
|
-
<input
|
|
945
|
-
type="checkbox"
|
|
946
|
-
role="switch"
|
|
947
|
-
checked={strip}
|
|
948
|
-
disabled={isLoading || pending}
|
|
949
|
-
onChange={(e) => {
|
|
950
|
-
void handleToggle(e.currentTarget.checked);
|
|
951
|
-
}}
|
|
952
|
-
className="size-4 cursor-pointer disabled:cursor-not-allowed disabled:opacity-50"
|
|
953
|
-
/>
|
|
954
|
-
<span className="text-sm">
|
|
955
|
-
{isLoading ? "Loading..." : strip ? "Stripping enabled" : "Stripping disabled"}
|
|
956
|
-
</span>
|
|
957
|
-
</label>
|
|
958
|
-
|
|
959
|
-
<div className="space-y-1">
|
|
960
|
-
<label htmlFor="slow-response-threshold" className="text-sm font-semibold">
|
|
961
|
-
Slow response threshold
|
|
962
|
-
</label>
|
|
963
|
-
<p className="text-xs text-muted-foreground">
|
|
964
|
-
Show a slow marker when elapsed time exceeds this many seconds. Use <code>0</code> to
|
|
965
|
-
disable it.
|
|
966
|
-
</p>
|
|
967
|
-
<div className="flex items-center gap-2">
|
|
968
|
-
<input
|
|
969
|
-
id="slow-response-threshold"
|
|
970
|
-
type="number"
|
|
971
|
-
min={0}
|
|
972
|
-
max={MAX_SLOW_RESPONSE_THRESHOLD_SECONDS}
|
|
973
|
-
step={1}
|
|
974
|
-
value={slowResponseThresholdSeconds}
|
|
975
|
-
disabled={isLoading || pending}
|
|
976
|
-
onChange={(e) => {
|
|
977
|
-
const next = Number(e.currentTarget.value);
|
|
978
|
-
if (!Number.isInteger(next)) return;
|
|
979
|
-
if (next < 0 || next > MAX_SLOW_RESPONSE_THRESHOLD_SECONDS) return;
|
|
980
|
-
void handleThresholdChange(next);
|
|
981
|
-
}}
|
|
982
|
-
className="h-8 w-24 rounded-md border border-input bg-transparent px-2 text-sm font-mono disabled:cursor-not-allowed disabled:opacity-50"
|
|
983
|
-
/>
|
|
984
|
-
<span className="text-xs text-muted-foreground">seconds</span>
|
|
985
|
-
</div>
|
|
986
|
-
</div>
|
|
987
|
-
|
|
988
|
-
<div className="space-y-1">
|
|
989
|
-
<label htmlFor="provider-test-timeout" className="text-sm font-semibold">
|
|
990
|
-
Provider test timeout
|
|
991
|
-
</label>
|
|
992
|
-
<p className="text-xs text-muted-foreground">
|
|
993
|
-
Abort slow Provider Test probes after this many seconds per model.
|
|
994
|
-
</p>
|
|
995
|
-
<div className="flex items-center gap-2">
|
|
996
|
-
<input
|
|
997
|
-
id="provider-test-timeout"
|
|
998
|
-
type="number"
|
|
999
|
-
min={1}
|
|
1000
|
-
max={MAX_PROVIDER_TEST_TIMEOUT_SECONDS}
|
|
1001
|
-
step={1}
|
|
1002
|
-
value={providerTestTimeoutSeconds}
|
|
1003
|
-
disabled={isLoading || pending}
|
|
1004
|
-
onChange={(e) => {
|
|
1005
|
-
const next = Number(e.currentTarget.value);
|
|
1006
|
-
if (!Number.isInteger(next)) return;
|
|
1007
|
-
if (next < 1 || next > MAX_PROVIDER_TEST_TIMEOUT_SECONDS) return;
|
|
1008
|
-
void handleProviderTestTimeoutChange(next);
|
|
1009
|
-
}}
|
|
1010
|
-
className="h-8 w-24 rounded-md border border-input bg-transparent px-2 text-sm font-mono disabled:cursor-not-allowed disabled:opacity-50"
|
|
1011
|
-
/>
|
|
1012
|
-
<span className="text-xs text-muted-foreground">seconds / model</span>
|
|
1013
|
-
</div>
|
|
1014
|
-
</div>
|
|
1015
|
-
|
|
1016
|
-
<div className="space-y-1">
|
|
1017
|
-
<label htmlFor="time-display-format" className="text-sm font-semibold">
|
|
1018
|
-
Time display
|
|
1019
|
-
</label>
|
|
1020
|
-
<p className="text-xs text-muted-foreground">
|
|
1021
|
-
Controls timestamps in session summaries, headers, and log rows.
|
|
1022
|
-
</p>
|
|
1023
|
-
<select
|
|
1024
|
-
id="time-display-format"
|
|
1025
|
-
value={timeDisplayFormat}
|
|
1026
|
-
disabled={isLoading || pending}
|
|
1027
|
-
onChange={(event) => {
|
|
1028
|
-
const parsed = TimeDisplayFormatSchema.safeParse(event.currentTarget.value);
|
|
1029
|
-
if (!parsed.success) return;
|
|
1030
|
-
void handleTimeDisplayFormatChange(parsed.data);
|
|
1031
|
-
}}
|
|
1032
|
-
className="h-8 rounded-md border border-input bg-background px-2 text-sm disabled:cursor-not-allowed disabled:opacity-50"
|
|
1033
|
-
>
|
|
1034
|
-
<option value="time">Time only</option>
|
|
1035
|
-
<option value="full">Full ISO</option>
|
|
1036
|
-
</select>
|
|
1037
|
-
</div>
|
|
1038
|
-
|
|
1039
|
-
{error !== null && <p className="text-xs text-destructive">Failed to save: {error}</p>}
|
|
1040
|
-
</div>
|
|
1041
|
-
);
|
|
1042
|
-
}
|