@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
package/src/lib/ssrfGuard.ts
DELETED
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* SSRF guard for upstream provider URLs.
|
|
3
|
-
*
|
|
4
|
-
* The proxy fetches arbitrary provider-configured base URLs (Anthropic, OpenAI,
|
|
5
|
-
* third-party compatible endpoints). Without protection, a malicious provider
|
|
6
|
-
* config could point the proxy at cloud metadata endpoints
|
|
7
|
-
* (169.254.169.254 / fd00:ec2::254), loopback services, or private RFC1918
|
|
8
|
-
* ranges — and the response body is captured to a log file the attacker can
|
|
9
|
-
* read back. We block those targets by default; an env var opt-in allows
|
|
10
|
-
* intentional localhost development (e.g. Ollama on 127.0.0.1).
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
export type SsrfDecision = { allow: true } | { allow: false; reason: string };
|
|
14
|
-
|
|
15
|
-
const LOOPBACK_HOSTNAMES = new Set([
|
|
16
|
-
"localhost",
|
|
17
|
-
"ip6-localhost",
|
|
18
|
-
"ip6-loopback",
|
|
19
|
-
"[::1]",
|
|
20
|
-
"[::ffff:127.0.0.1]",
|
|
21
|
-
]);
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Returns true when the host is a loopback address, link-local address, or
|
|
25
|
-
* private RFC1918 / RFC4193 / unique-local range. Both IPv4 dotted-quad and
|
|
26
|
-
* IPv6 forms are recognized; bracketed forms (`[::1]`) are normalized.
|
|
27
|
-
*/
|
|
28
|
-
function isLoopbackHost(hostname: string): boolean {
|
|
29
|
-
const lower = hostname.toLowerCase().replace(/^\[|]$/g, "");
|
|
30
|
-
if (LOOPBACK_HOSTNAMES.has(lower)) return true;
|
|
31
|
-
if (lower === "::1") return true;
|
|
32
|
-
if (lower.startsWith("::ffff:127.")) return true;
|
|
33
|
-
if (lower.startsWith("::ffff:7f00:")) return true;
|
|
34
|
-
return /^127\./.test(lower);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
function mappedIpv4Address(hostname: string): string | null {
|
|
38
|
-
const lower = hostname.toLowerCase();
|
|
39
|
-
if (!lower.startsWith("::ffff:")) return null;
|
|
40
|
-
const suffix = lower.slice("::ffff:".length);
|
|
41
|
-
if (/^\d{1,3}(?:\.\d{1,3}){3}$/.test(suffix)) return suffix;
|
|
42
|
-
const match = /^([0-9a-f]{1,4}):([0-9a-f]{1,4})$/.exec(suffix);
|
|
43
|
-
if (match === null) return null;
|
|
44
|
-
const highText = match[1];
|
|
45
|
-
const lowText = match[2];
|
|
46
|
-
if (highText === undefined || lowText === undefined) return null;
|
|
47
|
-
const high = Number.parseInt(highText, 16);
|
|
48
|
-
const low = Number.parseInt(lowText, 16);
|
|
49
|
-
return `${String(high >> 8)}.${String(high & 0xff)}.${String(low >> 8)}.${String(low & 0xff)}`;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export function isInternalHost(hostname: string): boolean {
|
|
53
|
-
if (LOOPBACK_HOSTNAMES.has(hostname.toLowerCase())) return true;
|
|
54
|
-
|
|
55
|
-
const mappedIpv4 = mappedIpv4Address(hostname);
|
|
56
|
-
if (mappedIpv4 !== null) return isInternalHost(mappedIpv4);
|
|
57
|
-
|
|
58
|
-
const ipv4Match = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/.exec(hostname);
|
|
59
|
-
if (ipv4Match !== null) {
|
|
60
|
-
const [, a, b] = ipv4Match;
|
|
61
|
-
if (a === undefined || b === undefined) return false;
|
|
62
|
-
const first = Number.parseInt(a, 10);
|
|
63
|
-
const second = Number.parseInt(b, 10);
|
|
64
|
-
if (first === 127) return true; // 127.0.0.0/8 loopback
|
|
65
|
-
if (first === 10) return true; // 10.0.0.0/8 private
|
|
66
|
-
if (first === 172 && second >= 16 && second <= 31) return true; // 172.16.0.0/12
|
|
67
|
-
if (first === 192 && second === 168) return true; // 192.168.0.0/16
|
|
68
|
-
if (first === 169 && second === 254) return true; // 169.254.0.0/16 link-local
|
|
69
|
-
if (first === 0) return true; // 0.0.0.0/8
|
|
70
|
-
if (first === 100 && second >= 64 && second <= 127) return true; // 100.64.0.0/10 CGNAT
|
|
71
|
-
if (first >= 224) return true; // multicast and reserved
|
|
72
|
-
if (first === 198 && (second === 18 || second === 19)) return true; // benchmark range
|
|
73
|
-
return false;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// IPv6 — bracketless form already stripped by URL parser; check for loopback
|
|
77
|
-
// and link-local prefixes.
|
|
78
|
-
const lower = hostname.toLowerCase();
|
|
79
|
-
if (lower === "::") return true;
|
|
80
|
-
if (lower === "::1") return true;
|
|
81
|
-
if (/^fe[89ab]/.test(lower)) return true; // fe80::/10 link-local
|
|
82
|
-
if (lower.startsWith("fc") || lower.startsWith("fd")) return true; // ULA (fd00::/8)
|
|
83
|
-
if (lower.startsWith("ff")) return true; // multicast
|
|
84
|
-
|
|
85
|
-
return false;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
export type SsrfGuardOptions = {
|
|
89
|
-
/** Bypass the guard entirely (used by trusted test code). */
|
|
90
|
-
bypass?: boolean;
|
|
91
|
-
/** When true, allow loopback hosts (127.0.0.1, ::1, localhost). Default false. */
|
|
92
|
-
allowLoopback?: boolean;
|
|
93
|
-
};
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Inspects a provider base URL and decides whether the proxy is allowed to
|
|
97
|
-
* forward requests to it. Returns `{ allow: true }` for public hosts and
|
|
98
|
-
* `{ allow: false, reason }` for internal/private addresses.
|
|
99
|
-
*/
|
|
100
|
-
export function evaluateUpstreamUrl(rawUrl: string, options: SsrfGuardOptions = {}): SsrfDecision {
|
|
101
|
-
if (options.bypass === true) return { allow: true };
|
|
102
|
-
|
|
103
|
-
let parsed: URL;
|
|
104
|
-
try {
|
|
105
|
-
parsed = new URL(rawUrl);
|
|
106
|
-
} catch {
|
|
107
|
-
return { allow: false, reason: "Not a valid URL" };
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
111
|
-
return { allow: false, reason: `Unsupported scheme "${parsed.protocol}"` };
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
if (options.allowLoopback === true && parsed.hostname === "localhost") {
|
|
115
|
-
return { allow: true };
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
// Bun's URL parser keeps brackets on IPv6 hostnames (`[::1]`); strip them so
|
|
119
|
-
// prefix checks below work against the canonical form.
|
|
120
|
-
const hostname = parsed.hostname.replace(/^\[|]$/g, "");
|
|
121
|
-
|
|
122
|
-
if (isInternalHost(hostname)) {
|
|
123
|
-
if (options.allowLoopback === true) {
|
|
124
|
-
if (isLoopbackHost(hostname)) return { allow: true };
|
|
125
|
-
}
|
|
126
|
-
return {
|
|
127
|
-
allow: false,
|
|
128
|
-
reason: `Refusing to proxy to internal address "${hostname}"`,
|
|
129
|
-
};
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
return { allow: true };
|
|
133
|
-
}
|
package/src/lib/stopReason.ts
DELETED
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
import type { CapturedLog, StopReason } from "../contracts";
|
|
2
|
-
import { isRecord } from "./unknown";
|
|
3
|
-
|
|
4
|
-
export type { StopReason } from "../contracts";
|
|
5
|
-
|
|
6
|
-
function normalizeAnthropicStopReason(value: string): StopReason {
|
|
7
|
-
switch (value) {
|
|
8
|
-
case "end_turn":
|
|
9
|
-
case "tool_use":
|
|
10
|
-
return value;
|
|
11
|
-
case "max_tokens":
|
|
12
|
-
return "length";
|
|
13
|
-
default:
|
|
14
|
-
return null;
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
function extractStopReasonFromJsonValue(value: unknown): StopReason {
|
|
19
|
-
if (!isRecord(value)) return null;
|
|
20
|
-
|
|
21
|
-
// Anthropic shape: { stop_reason: "end_turn" | "tool_use" | ... }
|
|
22
|
-
if (typeof value.stop_reason === "string") {
|
|
23
|
-
return normalizeAnthropicStopReason(value.stop_reason);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
// Anthropic SSE shape: { type: "message_delta", delta: { stop_reason: "..." } }
|
|
27
|
-
if (isRecord(value.delta) && typeof value.delta.stop_reason === "string") {
|
|
28
|
-
return normalizeAnthropicStopReason(value.delta.stop_reason);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// OpenAI Chat shape: { choices: [{ finish_reason: "stop" | "length" | ... }] }
|
|
32
|
-
if (Array.isArray(value.choices)) {
|
|
33
|
-
for (const choice of value.choices) {
|
|
34
|
-
if (!isRecord(choice) || typeof choice.finish_reason !== "string") continue;
|
|
35
|
-
const reason = normalizeOpenAIFinishReason(choice.finish_reason);
|
|
36
|
-
if (reason !== null) return reason;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// OpenAI Responses shape: { status: "completed", output: [...] }
|
|
41
|
-
if (Array.isArray(value.output)) {
|
|
42
|
-
for (const item of value.output) {
|
|
43
|
-
if (isRecord(item) && item.type === "function_call") {
|
|
44
|
-
return "tool_use";
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
if (value.status === "completed") {
|
|
48
|
-
return "stop";
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
if (value.status === "incomplete" && isRecord(value.incomplete_details)) {
|
|
53
|
-
const reason = value.incomplete_details.reason;
|
|
54
|
-
if (typeof reason === "string" && isResponsesLengthLimitReason(reason)) {
|
|
55
|
-
return "length";
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
return null;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
function extractStopReasonFromSseText(text: string): StopReason {
|
|
63
|
-
let stopReason: StopReason = null;
|
|
64
|
-
for (const rawLine of text.split("\n")) {
|
|
65
|
-
const line = rawLine.trim();
|
|
66
|
-
if (!line.startsWith("data: ")) continue;
|
|
67
|
-
const data = line.slice(6).trim();
|
|
68
|
-
if (data === "[DONE]") break;
|
|
69
|
-
try {
|
|
70
|
-
const reason = extractStopReasonFromJsonValue(JSON.parse(data));
|
|
71
|
-
if (reason !== null) stopReason = reason;
|
|
72
|
-
} catch {
|
|
73
|
-
// Ignore malformed or non-JSON SSE data lines.
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
return stopReason;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
function normalizeOpenAIFinishReason(value: string): StopReason {
|
|
80
|
-
switch (value) {
|
|
81
|
-
case "stop":
|
|
82
|
-
case "length":
|
|
83
|
-
return value;
|
|
84
|
-
case "max_tokens":
|
|
85
|
-
return "length";
|
|
86
|
-
default:
|
|
87
|
-
return null;
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
function isResponsesLengthLimitReason(value: string): boolean {
|
|
92
|
-
switch (value) {
|
|
93
|
-
case "max_output_tokens":
|
|
94
|
-
case "max_tokens":
|
|
95
|
-
return true;
|
|
96
|
-
default:
|
|
97
|
-
return false;
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Extracts the stop/finish reason from a captured log's response text.
|
|
103
|
-
* Detects the response body shape (Anthropic or OpenAI) independently of
|
|
104
|
-
* `log.apiFormat`, since the body shape may not match the declared format
|
|
105
|
-
* (e.g. an Anthropic-compatible endpoint returning Anthropic-shaped JSON
|
|
106
|
-
* while the request was classified as OpenAI).
|
|
107
|
-
*/
|
|
108
|
-
export function extractStopReason(log: CapturedLog): StopReason {
|
|
109
|
-
if (log.stopReason !== undefined) return log.stopReason;
|
|
110
|
-
if (log.responseText === null) return null;
|
|
111
|
-
|
|
112
|
-
try {
|
|
113
|
-
let json: unknown = JSON.parse(log.responseText);
|
|
114
|
-
// Handle double-encoded JSON
|
|
115
|
-
if (typeof json === "string") {
|
|
116
|
-
json = JSON.parse(json);
|
|
117
|
-
}
|
|
118
|
-
return extractStopReasonFromJsonValue(json);
|
|
119
|
-
} catch {
|
|
120
|
-
return extractStopReasonFromSseText(log.responseText);
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
/**
|
|
125
|
-
* Returns true when the stop reason indicates the assistant completed its
|
|
126
|
-
* turn, including responses truncated by output length limits.
|
|
127
|
-
*/
|
|
128
|
-
export function isTurnBoundary(stopReason: StopReason): boolean {
|
|
129
|
-
return stopReason === "end_turn" || stopReason === "stop" || stopReason === "length";
|
|
130
|
-
}
|
package/src/lib/themeMode.ts
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
export type ThemeMode = "light" | "dark" | "eye-care";
|
|
2
|
-
|
|
3
|
-
export const THEME_MODE_STORAGE_KEY = "agent-inspector.theme";
|
|
4
|
-
|
|
5
|
-
export function normalizeThemeMode(value: string | null): ThemeMode {
|
|
6
|
-
switch (value) {
|
|
7
|
-
case "light":
|
|
8
|
-
return "light";
|
|
9
|
-
case "dark":
|
|
10
|
-
return "dark";
|
|
11
|
-
case "eye-care":
|
|
12
|
-
return "eye-care";
|
|
13
|
-
case null:
|
|
14
|
-
return "dark";
|
|
15
|
-
default:
|
|
16
|
-
return "dark";
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export function applyThemeMode(themeMode: ThemeMode): void {
|
|
21
|
-
if (typeof document === "undefined") return;
|
|
22
|
-
document.documentElement.dataset.theme = themeMode;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export function readStoredThemeMode(): ThemeMode {
|
|
26
|
-
if (typeof window === "undefined") return "dark";
|
|
27
|
-
try {
|
|
28
|
-
return normalizeThemeMode(window.localStorage.getItem(THEME_MODE_STORAGE_KEY));
|
|
29
|
-
} catch {
|
|
30
|
-
return "dark";
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export function persistThemeMode(themeMode: ThemeMode): void {
|
|
35
|
-
if (typeof window === "undefined") return;
|
|
36
|
-
try {
|
|
37
|
-
window.localStorage.setItem(THEME_MODE_STORAGE_KEY, themeMode);
|
|
38
|
-
} catch {
|
|
39
|
-
// Local storage can be unavailable in hardened browser contexts.
|
|
40
|
-
}
|
|
41
|
-
}
|
package/src/lib/timeDisplay.ts
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import type { TimeDisplayFormat } from "./runtimeConfig";
|
|
2
|
-
|
|
3
|
-
export function formatTimestamp(iso: string, format: TimeDisplayFormat): string {
|
|
4
|
-
switch (format) {
|
|
5
|
-
case "full":
|
|
6
|
-
return iso;
|
|
7
|
-
case "time":
|
|
8
|
-
return new Date(iso).toLocaleTimeString([], {
|
|
9
|
-
hour: "2-digit",
|
|
10
|
-
minute: "2-digit",
|
|
11
|
-
second: "2-digit",
|
|
12
|
-
});
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export function formatTimestampRange(
|
|
17
|
-
startedAt: string,
|
|
18
|
-
endedAt: string,
|
|
19
|
-
format: TimeDisplayFormat,
|
|
20
|
-
): string {
|
|
21
|
-
return `${formatTimestamp(startedAt, format)} - ${formatTimestamp(endedAt, format)}`;
|
|
22
|
-
}
|
package/src/lib/toolTrace.ts
DELETED
|
@@ -1,290 +0,0 @@
|
|
|
1
|
-
import type { ApiFormat, CapturedLog, StreamingChunk, ToolTraceEvent } from "../contracts";
|
|
2
|
-
import { apiFormatForPath } from "./apiFormat";
|
|
3
|
-
import { safeGetOwnProperty } from "./objectUtils";
|
|
4
|
-
|
|
5
|
-
export type { ToolTraceEvent };
|
|
6
|
-
|
|
7
|
-
const PREVIEW_LIMIT = 180;
|
|
8
|
-
|
|
9
|
-
type ResolvedLogFormat = ApiFormat;
|
|
10
|
-
|
|
11
|
-
function resolveLogFormat(log: Pick<CapturedLog, "path" | "apiFormat">): ResolvedLogFormat {
|
|
12
|
-
const pathFormat = apiFormatForPath(log.path);
|
|
13
|
-
return pathFormat === "unknown" ? log.apiFormat : pathFormat;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
function responseMayContainToolTrace(log: CapturedLog, format: ResolvedLogFormat): boolean {
|
|
17
|
-
const responseText = log.responseText;
|
|
18
|
-
if (responseText === null) return false;
|
|
19
|
-
|
|
20
|
-
switch (format) {
|
|
21
|
-
case "anthropic":
|
|
22
|
-
return responseText.includes("tool_use");
|
|
23
|
-
case "openai":
|
|
24
|
-
return responseText.includes("tool_calls") || responseText.includes("function_call");
|
|
25
|
-
case "unknown":
|
|
26
|
-
return false;
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function parseJsonResponse(responseText: string | null): unknown {
|
|
31
|
-
if (responseText === null) return null;
|
|
32
|
-
try {
|
|
33
|
-
const parsed: unknown = JSON.parse(responseText);
|
|
34
|
-
if (typeof parsed === "string") {
|
|
35
|
-
return JSON.parse(parsed);
|
|
36
|
-
}
|
|
37
|
-
return parsed;
|
|
38
|
-
} catch {
|
|
39
|
-
return null;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
function previewValue(value: unknown): string | null {
|
|
44
|
-
if (value === undefined || value === null) return null;
|
|
45
|
-
const raw = typeof value === "string" ? value : JSON.stringify(value);
|
|
46
|
-
if (raw === undefined) return null;
|
|
47
|
-
const normalized = raw.replace(/\s+/g, " ").trim();
|
|
48
|
-
if (normalized.length === 0) return null;
|
|
49
|
-
return normalized.length > PREVIEW_LIMIT
|
|
50
|
-
? `${normalized.slice(0, PREVIEW_LIMIT - 1)}...`
|
|
51
|
-
: normalized;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
function copyValue(value: unknown): string | null {
|
|
55
|
-
if (value === undefined || value === null) return null;
|
|
56
|
-
if (typeof value === "string") return value.length > 0 ? value : null;
|
|
57
|
-
const raw = JSON.stringify(value, null, 2);
|
|
58
|
-
return raw === undefined || raw.length === 0 ? null : raw;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
function makeEvent({
|
|
62
|
-
log,
|
|
63
|
-
provider,
|
|
64
|
-
index,
|
|
65
|
-
name,
|
|
66
|
-
input,
|
|
67
|
-
}: {
|
|
68
|
-
log: Pick<CapturedLog, "id">;
|
|
69
|
-
provider: "anthropic" | "openai";
|
|
70
|
-
index: number;
|
|
71
|
-
name: string;
|
|
72
|
-
input: unknown;
|
|
73
|
-
}): ToolTraceEvent {
|
|
74
|
-
return {
|
|
75
|
-
id: `${String(log.id)}-${provider}-tool-${String(index)}`,
|
|
76
|
-
logId: log.id,
|
|
77
|
-
index,
|
|
78
|
-
provider,
|
|
79
|
-
name,
|
|
80
|
-
argumentsText: copyValue(input),
|
|
81
|
-
argumentsPreview: previewValue(input),
|
|
82
|
-
};
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
function extractAnthropicResponseToolTraceEvents(log: CapturedLog): ToolTraceEvent[] {
|
|
86
|
-
const parsed = parseJsonResponse(log.responseText);
|
|
87
|
-
const content = safeGetOwnProperty(parsed, "content");
|
|
88
|
-
if (!Array.isArray(content)) return [];
|
|
89
|
-
|
|
90
|
-
const events: ToolTraceEvent[] = [];
|
|
91
|
-
for (const block of content) {
|
|
92
|
-
const type = safeGetOwnProperty(block, "type");
|
|
93
|
-
if (type !== "tool_use") continue;
|
|
94
|
-
const name = safeGetOwnProperty(block, "name");
|
|
95
|
-
if (typeof name !== "string" || name.length === 0) continue;
|
|
96
|
-
const input = safeGetOwnProperty(block, "input");
|
|
97
|
-
events.push(makeEvent({ log, provider: "anthropic", index: events.length, name, input }));
|
|
98
|
-
}
|
|
99
|
-
return events;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
function extractOpenAIResponseToolTraceEvents(log: CapturedLog): ToolTraceEvent[] {
|
|
103
|
-
const parsed = parseJsonResponse(log.responseText);
|
|
104
|
-
const choices = safeGetOwnProperty(parsed, "choices");
|
|
105
|
-
const events: ToolTraceEvent[] = [];
|
|
106
|
-
|
|
107
|
-
if (Array.isArray(choices)) {
|
|
108
|
-
for (const choice of choices) {
|
|
109
|
-
const message = safeGetOwnProperty(choice, "message");
|
|
110
|
-
const toolCalls = safeGetOwnProperty(message, "tool_calls");
|
|
111
|
-
if (Array.isArray(toolCalls)) {
|
|
112
|
-
for (const call of toolCalls) {
|
|
113
|
-
const fn = safeGetOwnProperty(call, "function");
|
|
114
|
-
const name = safeGetOwnProperty(fn, "name");
|
|
115
|
-
if (typeof name !== "string" || name.length === 0) continue;
|
|
116
|
-
const args = safeGetOwnProperty(fn, "arguments");
|
|
117
|
-
events.push(
|
|
118
|
-
makeEvent({ log, provider: "openai", index: events.length, name, input: args }),
|
|
119
|
-
);
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
const functionCall = safeGetOwnProperty(message, "function_call");
|
|
123
|
-
const functionCallName = safeGetOwnProperty(functionCall, "name");
|
|
124
|
-
if (typeof functionCallName === "string" && functionCallName.length > 0) {
|
|
125
|
-
const args = safeGetOwnProperty(functionCall, "arguments");
|
|
126
|
-
events.push(
|
|
127
|
-
makeEvent({
|
|
128
|
-
log,
|
|
129
|
-
provider: "openai",
|
|
130
|
-
index: events.length,
|
|
131
|
-
name: functionCallName,
|
|
132
|
-
input: args,
|
|
133
|
-
}),
|
|
134
|
-
);
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
const output = safeGetOwnProperty(parsed, "output");
|
|
140
|
-
if (Array.isArray(output)) {
|
|
141
|
-
for (const item of output) {
|
|
142
|
-
if (safeGetOwnProperty(item, "type") !== "function_call") continue;
|
|
143
|
-
const name = safeGetOwnProperty(item, "name");
|
|
144
|
-
if (typeof name !== "string" || name.length === 0) continue;
|
|
145
|
-
const args = safeGetOwnProperty(item, "arguments");
|
|
146
|
-
events.push(makeEvent({ log, provider: "openai", index: events.length, name, input: args }));
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
return events;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
function chunkData(chunk: StreamingChunk): unknown {
|
|
153
|
-
if (typeof chunk.data === "string") {
|
|
154
|
-
try {
|
|
155
|
-
return JSON.parse(chunk.data);
|
|
156
|
-
} catch {
|
|
157
|
-
return chunk.data;
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
return chunk.data;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
function appendUniqueEvent(
|
|
164
|
-
events: ToolTraceEvent[],
|
|
165
|
-
seen: Set<string>,
|
|
166
|
-
event: ToolTraceEvent,
|
|
167
|
-
): void {
|
|
168
|
-
const key = `${event.provider}:${event.name}:${event.index}`;
|
|
169
|
-
if (seen.has(key)) return;
|
|
170
|
-
seen.add(key);
|
|
171
|
-
events.push(event);
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
function extractAnthropicChunkToolTraceEvents(log: CapturedLog): ToolTraceEvent[] {
|
|
175
|
-
const chunks = log.streamingChunks?.chunks ?? [];
|
|
176
|
-
const events: ToolTraceEvent[] = [];
|
|
177
|
-
const seen = new Set<string>();
|
|
178
|
-
|
|
179
|
-
for (const chunk of chunks) {
|
|
180
|
-
const data = chunkData(chunk);
|
|
181
|
-
const contentBlock = safeGetOwnProperty(data, "content_block");
|
|
182
|
-
if (safeGetOwnProperty(contentBlock, "type") !== "tool_use") continue;
|
|
183
|
-
const name = safeGetOwnProperty(contentBlock, "name");
|
|
184
|
-
if (typeof name !== "string" || name.length === 0) continue;
|
|
185
|
-
const input = safeGetOwnProperty(contentBlock, "input");
|
|
186
|
-
appendUniqueEvent(
|
|
187
|
-
events,
|
|
188
|
-
seen,
|
|
189
|
-
makeEvent({ log, provider: "anthropic", index: chunk.index, name, input }),
|
|
190
|
-
);
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
return events.map((event, index) => ({
|
|
194
|
-
...event,
|
|
195
|
-
id: `${String(log.id)}-anthropic-tool-${String(index)}`,
|
|
196
|
-
index,
|
|
197
|
-
}));
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
function extractOpenAIChunkToolTraceEvents(log: CapturedLog): ToolTraceEvent[] {
|
|
201
|
-
const chunks = log.streamingChunks?.chunks ?? [];
|
|
202
|
-
const events: ToolTraceEvent[] = [];
|
|
203
|
-
const seen = new Set<string>();
|
|
204
|
-
|
|
205
|
-
for (const chunk of chunks) {
|
|
206
|
-
const data = chunkData(chunk);
|
|
207
|
-
const choices = safeGetOwnProperty(data, "choices");
|
|
208
|
-
if (Array.isArray(choices)) {
|
|
209
|
-
for (const choice of choices) {
|
|
210
|
-
const delta = safeGetOwnProperty(choice, "delta");
|
|
211
|
-
const toolCalls = safeGetOwnProperty(delta, "tool_calls");
|
|
212
|
-
if (Array.isArray(toolCalls)) {
|
|
213
|
-
for (const call of toolCalls) {
|
|
214
|
-
const fn = safeGetOwnProperty(call, "function");
|
|
215
|
-
const name = safeGetOwnProperty(fn, "name");
|
|
216
|
-
if (typeof name !== "string" || name.length === 0) continue;
|
|
217
|
-
const args = safeGetOwnProperty(fn, "arguments");
|
|
218
|
-
appendUniqueEvent(
|
|
219
|
-
events,
|
|
220
|
-
seen,
|
|
221
|
-
makeEvent({ log, provider: "openai", index: events.length, name, input: args }),
|
|
222
|
-
);
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
const functionCall = safeGetOwnProperty(delta, "function_call");
|
|
226
|
-
const functionCallName = safeGetOwnProperty(functionCall, "name");
|
|
227
|
-
if (typeof functionCallName === "string" && functionCallName.length > 0) {
|
|
228
|
-
const args = safeGetOwnProperty(functionCall, "arguments");
|
|
229
|
-
appendUniqueEvent(
|
|
230
|
-
events,
|
|
231
|
-
seen,
|
|
232
|
-
makeEvent({
|
|
233
|
-
log,
|
|
234
|
-
provider: "openai",
|
|
235
|
-
index: events.length,
|
|
236
|
-
name: functionCallName,
|
|
237
|
-
input: args,
|
|
238
|
-
}),
|
|
239
|
-
);
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
const item = safeGetOwnProperty(data, "item");
|
|
245
|
-
if (safeGetOwnProperty(item, "type") === "function_call") {
|
|
246
|
-
const name = safeGetOwnProperty(item, "name");
|
|
247
|
-
if (typeof name === "string" && name.length > 0) {
|
|
248
|
-
const args = safeGetOwnProperty(item, "arguments");
|
|
249
|
-
appendUniqueEvent(
|
|
250
|
-
events,
|
|
251
|
-
seen,
|
|
252
|
-
makeEvent({ log, provider: "openai", index: events.length, name, input: args }),
|
|
253
|
-
);
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
return events.map((event, index) => ({
|
|
259
|
-
...event,
|
|
260
|
-
id: `${String(log.id)}-openai-tool-${String(index)}`,
|
|
261
|
-
index,
|
|
262
|
-
}));
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
export function extractToolTraceEvents(log: CapturedLog): ToolTraceEvent[] {
|
|
266
|
-
if (log.toolTraceEvents !== undefined && log.toolTraceEvents.length > 0) {
|
|
267
|
-
return log.toolTraceEvents;
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
const format = resolveLogFormat(log);
|
|
271
|
-
if (responseMayContainToolTrace(log, format)) {
|
|
272
|
-
switch (format) {
|
|
273
|
-
case "anthropic":
|
|
274
|
-
return extractAnthropicResponseToolTraceEvents(log);
|
|
275
|
-
case "openai":
|
|
276
|
-
return extractOpenAIResponseToolTraceEvents(log);
|
|
277
|
-
case "unknown":
|
|
278
|
-
return [];
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
switch (format) {
|
|
283
|
-
case "anthropic":
|
|
284
|
-
return extractAnthropicChunkToolTraceEvents(log);
|
|
285
|
-
case "openai":
|
|
286
|
-
return extractOpenAIChunkToolTraceEvents(log);
|
|
287
|
-
case "unknown":
|
|
288
|
-
return [];
|
|
289
|
-
}
|
|
290
|
-
}
|