@tonyclaw/agent-inspector 3.1.32 → 4.0.2
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 +241 -120
- package/.output/server/_ssr/index.mjs +1 -1
- package/.output/server/_ssr/{router-oXUk3MBR.mjs → router-BBY_zWRK.mjs} +91 -3
- package/.output/server/index.mjs +1 -1
- package/.output/ui/assets/{CompareDrawer-BtfPSpkV.js → CompareDrawer-rtNElN-B.js} +1 -1
- package/.output/ui/assets/{InspectorPet-D9DPPQ3n.js → InspectorPet-QaAiuF3d.js} +1 -1
- package/.output/ui/assets/{ProxyViewerContainer-Buu8vkCK.js → ProxyViewerContainer-6twNZHwl.js} +4 -4
- package/.output/ui/assets/{ReplayDialog-BER-QzpD.js → ReplayDialog-B7KlziO2.js} +1 -1
- package/.output/ui/assets/{RequestAnatomy-C8Zwxrr7.js → RequestAnatomy-2XVFBrW4.js} +1 -1
- package/.output/ui/assets/{ResponseView-DDpKdYk6.js → ResponseView-BULgzLVB.js} +1 -1
- package/.output/ui/assets/{StreamingChunkSequence-sMPGG7Sw.js → StreamingChunkSequence-DSkvkbns.js} +1 -1
- package/.output/ui/assets/{_sessionId-e4IheHnP.js → _sessionId-D2dmJi3G.js} +1 -1
- package/.output/ui/assets/{_sessionId-C5Uv72Fx.js → _sessionId-DcS0s1Mr.js} +1 -1
- package/.output/ui/assets/{index-B__qT0Yd.js → index-B0TN1KKO.js} +2 -2
- package/.output/ui/assets/{index-Be3bTCzi.js → index-Bva1zHEs.js} +1 -1
- package/.output/ui/assets/{index-C9q__p8J.js → index-BzBExOxu.js} +1 -1
- package/.output/ui/assets/{index-CtB0deSZ.js → index-k6sRQz55.js} +1 -1
- package/.output/ui/assets/{json-viewer-Db0AFp-7.js → json-viewer-CWM4tY-j.js} +1 -1
- package/.output/ui/assets/{jszip.min-DkY0Ym_q.js → jszip.min-BkWvRFlo.js} +1 -1
- package/.output/ui/index.html +1 -1
- package/package.json +8 -13
- 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 -1397
- 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 -253
- 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,31 +0,0 @@
|
|
|
1
|
-
import type { StreamingChunk } from "./schemas";
|
|
2
|
-
|
|
3
|
-
export function computeTokensPerSecond({
|
|
4
|
-
outputTokens,
|
|
5
|
-
firstChunkMs,
|
|
6
|
-
totalStreamMs,
|
|
7
|
-
}: {
|
|
8
|
-
outputTokens: number | null | undefined;
|
|
9
|
-
firstChunkMs: number | null | undefined;
|
|
10
|
-
totalStreamMs: number | null | undefined;
|
|
11
|
-
}): number | null {
|
|
12
|
-
if (outputTokens === null || outputTokens === undefined || outputTokens <= 0) return null;
|
|
13
|
-
if (totalStreamMs === null || totalStreamMs === undefined || totalStreamMs <= 0) return null;
|
|
14
|
-
|
|
15
|
-
const generationMs =
|
|
16
|
-
firstChunkMs === null || firstChunkMs === undefined
|
|
17
|
-
? totalStreamMs
|
|
18
|
-
: totalStreamMs - firstChunkMs;
|
|
19
|
-
if (!Number.isFinite(generationMs) || generationMs <= 0) return null;
|
|
20
|
-
|
|
21
|
-
return Number((outputTokens / (generationMs / 1000)).toFixed(2));
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export function firstChunkMsFromChunks(
|
|
25
|
-
chunks: readonly StreamingChunk[] | undefined,
|
|
26
|
-
): number | null {
|
|
27
|
-
const first = chunks?.[0];
|
|
28
|
-
if (first === undefined) return null;
|
|
29
|
-
if (!Number.isFinite(first.timestamp) || first.timestamp < 0) return null;
|
|
30
|
-
return Math.floor(first.timestamp);
|
|
31
|
-
}
|
|
@@ -1,529 +0,0 @@
|
|
|
1
|
-
import type { ApiFormat } from "./schemas";
|
|
2
|
-
import { isRecord, readProperty } from "../lib/unknown";
|
|
3
|
-
|
|
4
|
-
type JsonObject = Record<string, unknown>;
|
|
5
|
-
|
|
6
|
-
type ExpectedJsonType = "array" | "boolean" | "integer" | "null" | "number" | "object" | "string";
|
|
7
|
-
|
|
8
|
-
type ParsedJson = { ok: true; value: unknown } | { ok: false };
|
|
9
|
-
|
|
10
|
-
type ToolSchema = {
|
|
11
|
-
name: string;
|
|
12
|
-
schema: JsonObject | null;
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
type ToolCall = {
|
|
16
|
-
name: string | null;
|
|
17
|
-
arguments: unknown;
|
|
18
|
-
argumentIssue: string | null;
|
|
19
|
-
location: string;
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
export type ToolSchemaWarningInput = {
|
|
23
|
-
rawRequestBody: string | null;
|
|
24
|
-
responseText: string | null;
|
|
25
|
-
apiFormat: ApiFormat;
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
function parseJson(raw: string | null): ParsedJson {
|
|
29
|
-
if (raw === null) return { ok: false };
|
|
30
|
-
try {
|
|
31
|
-
return { ok: true, value: JSON.parse(raw) };
|
|
32
|
-
} catch {
|
|
33
|
-
return { ok: false };
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
function hasOwnProperty(value: JsonObject, key: string): boolean {
|
|
38
|
-
return Object.getOwnPropertyDescriptor(value, key) !== undefined;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
function readString(value: unknown, key: string): string | null {
|
|
42
|
-
const property = readProperty(value, key);
|
|
43
|
-
return typeof property === "string" ? property : null;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
function readArray(value: unknown, key: string): unknown[] {
|
|
47
|
-
const property = readProperty(value, key);
|
|
48
|
-
return Array.isArray(property) ? property : [];
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
function readStringArray(value: unknown, key: string): string[] {
|
|
52
|
-
return readArray(value, key).filter((item): item is string => typeof item === "string");
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
function readObject(value: unknown, key: string): JsonObject | null {
|
|
56
|
-
const property = readProperty(value, key);
|
|
57
|
-
return isRecord(property) ? property : null;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
function normalizeExpectedType(typeName: string): ExpectedJsonType | null {
|
|
61
|
-
switch (typeName) {
|
|
62
|
-
case "array":
|
|
63
|
-
case "boolean":
|
|
64
|
-
case "integer":
|
|
65
|
-
case "null":
|
|
66
|
-
case "number":
|
|
67
|
-
case "object":
|
|
68
|
-
case "string":
|
|
69
|
-
return typeName;
|
|
70
|
-
default:
|
|
71
|
-
return null;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
function schemaTypes(schema: JsonObject): ExpectedJsonType[] {
|
|
76
|
-
const typeValue = readProperty(schema, "type");
|
|
77
|
-
const rawTypes = Array.isArray(typeValue) ? typeValue : [typeValue];
|
|
78
|
-
const types: ExpectedJsonType[] = [];
|
|
79
|
-
for (const rawType of rawTypes) {
|
|
80
|
-
if (typeof rawType !== "string") continue;
|
|
81
|
-
const normalized = normalizeExpectedType(rawType);
|
|
82
|
-
if (normalized !== null && !types.includes(normalized)) {
|
|
83
|
-
types.push(normalized);
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
return types;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
function actualType(value: unknown): ExpectedJsonType | "undefined" | "unknown" {
|
|
90
|
-
if (value === null) return "null";
|
|
91
|
-
if (Array.isArray(value)) return "array";
|
|
92
|
-
|
|
93
|
-
switch (typeof value) {
|
|
94
|
-
case "boolean":
|
|
95
|
-
return "boolean";
|
|
96
|
-
case "number":
|
|
97
|
-
return Number.isInteger(value) ? "integer" : "number";
|
|
98
|
-
case "string":
|
|
99
|
-
return "string";
|
|
100
|
-
case "undefined":
|
|
101
|
-
return "undefined";
|
|
102
|
-
case "bigint":
|
|
103
|
-
case "function":
|
|
104
|
-
case "object":
|
|
105
|
-
case "symbol":
|
|
106
|
-
return isRecord(value) ? "object" : "unknown";
|
|
107
|
-
}
|
|
108
|
-
return "unknown";
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
function matchesExpectedType(value: unknown, expected: ExpectedJsonType): boolean {
|
|
112
|
-
switch (expected) {
|
|
113
|
-
case "array":
|
|
114
|
-
return Array.isArray(value);
|
|
115
|
-
case "boolean":
|
|
116
|
-
return typeof value === "boolean";
|
|
117
|
-
case "integer":
|
|
118
|
-
return typeof value === "number" && Number.isInteger(value);
|
|
119
|
-
case "null":
|
|
120
|
-
return value === null;
|
|
121
|
-
case "number":
|
|
122
|
-
return typeof value === "number" && Number.isFinite(value);
|
|
123
|
-
case "object":
|
|
124
|
-
return isRecord(value);
|
|
125
|
-
case "string":
|
|
126
|
-
return typeof value === "string";
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
function matchesAnyExpectedType(
|
|
131
|
-
value: unknown,
|
|
132
|
-
expectedTypes: readonly ExpectedJsonType[],
|
|
133
|
-
): boolean {
|
|
134
|
-
return expectedTypes.some((expected) => matchesExpectedType(value, expected));
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
function formatExpectedTypes(expectedTypes: readonly ExpectedJsonType[]): string {
|
|
138
|
-
return expectedTypes.join(" or ");
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
function pathLabel(path: string): string {
|
|
142
|
-
return path === "" ? "arguments" : `argument "${path}"`;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
function childPath(parent: string, key: string): string {
|
|
146
|
-
return parent === "" ? key : `${parent}.${key}`;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
function jsonString(value: unknown): string | null {
|
|
150
|
-
try {
|
|
151
|
-
const serialized = JSON.stringify(value);
|
|
152
|
-
return serialized === undefined ? null : serialized;
|
|
153
|
-
} catch {
|
|
154
|
-
return null;
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
function jsonValuesEqual(left: unknown, right: unknown): boolean {
|
|
159
|
-
const leftJson = jsonString(left);
|
|
160
|
-
const rightJson = jsonString(right);
|
|
161
|
-
return leftJson !== null && rightJson !== null && leftJson === rightJson;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
function formatJsonValue(value: unknown): string {
|
|
165
|
-
const serialized = jsonString(value);
|
|
166
|
-
return serialized ?? String(value);
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
function enumMatches(value: unknown, enumValues: readonly unknown[]): boolean {
|
|
170
|
-
return enumValues.some((enumValue) => jsonValuesEqual(value, enumValue));
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
function schemaHasObjectKeywords(schema: JsonObject): boolean {
|
|
174
|
-
return (
|
|
175
|
-
readStringArray(schema, "required").length > 0 || readObject(schema, "properties") !== null
|
|
176
|
-
);
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
function schemaAllowsObjectValidation(
|
|
180
|
-
schema: JsonObject,
|
|
181
|
-
expectedTypes: readonly ExpectedJsonType[],
|
|
182
|
-
): boolean {
|
|
183
|
-
if (expectedTypes.length === 0) return schemaHasObjectKeywords(schema);
|
|
184
|
-
return expectedTypes.includes("object");
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
function schemaAllowsArrayValidation(
|
|
188
|
-
schema: JsonObject,
|
|
189
|
-
expectedTypes: readonly ExpectedJsonType[],
|
|
190
|
-
): boolean {
|
|
191
|
-
if (expectedTypes.length === 0) return readProperty(schema, "items") !== undefined;
|
|
192
|
-
return expectedTypes.includes("array");
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
function addTypeWarning(
|
|
196
|
-
warnings: string[],
|
|
197
|
-
toolName: string,
|
|
198
|
-
path: string,
|
|
199
|
-
expectedTypes: readonly ExpectedJsonType[],
|
|
200
|
-
value: unknown,
|
|
201
|
-
): void {
|
|
202
|
-
warnings.push(
|
|
203
|
-
`Tool call "${toolName}" ${pathLabel(path)} expected ${formatExpectedTypes(
|
|
204
|
-
expectedTypes,
|
|
205
|
-
)} but got ${actualType(value)}.`,
|
|
206
|
-
);
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
function validateObjectSchema(
|
|
210
|
-
schema: JsonObject,
|
|
211
|
-
value: JsonObject,
|
|
212
|
-
toolName: string,
|
|
213
|
-
path: string,
|
|
214
|
-
warnings: string[],
|
|
215
|
-
): void {
|
|
216
|
-
for (const requiredName of readStringArray(schema, "required")) {
|
|
217
|
-
if (!hasOwnProperty(value, requiredName)) {
|
|
218
|
-
warnings.push(
|
|
219
|
-
`Tool call "${toolName}" is missing required ${pathLabel(childPath(path, requiredName))}.`,
|
|
220
|
-
);
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
const properties = readObject(schema, "properties");
|
|
225
|
-
if (properties === null) return;
|
|
226
|
-
for (const [propertyName, propertySchema] of Object.entries(properties)) {
|
|
227
|
-
const descriptor = Object.getOwnPropertyDescriptor(value, propertyName);
|
|
228
|
-
if (descriptor === undefined) continue;
|
|
229
|
-
validateValueAgainstSchema(
|
|
230
|
-
propertySchema,
|
|
231
|
-
descriptor.value,
|
|
232
|
-
toolName,
|
|
233
|
-
childPath(path, propertyName),
|
|
234
|
-
warnings,
|
|
235
|
-
);
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
function validateArraySchema(
|
|
240
|
-
schema: JsonObject,
|
|
241
|
-
value: readonly unknown[],
|
|
242
|
-
toolName: string,
|
|
243
|
-
path: string,
|
|
244
|
-
warnings: string[],
|
|
245
|
-
): void {
|
|
246
|
-
const itemsSchema = readProperty(schema, "items");
|
|
247
|
-
if (itemsSchema === undefined) return;
|
|
248
|
-
let index = 0;
|
|
249
|
-
for (const item of value) {
|
|
250
|
-
validateValueAgainstSchema(itemsSchema, item, toolName, `${path}[${index}]`, warnings);
|
|
251
|
-
index++;
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
function validateEnum(
|
|
256
|
-
schema: JsonObject,
|
|
257
|
-
value: unknown,
|
|
258
|
-
toolName: string,
|
|
259
|
-
path: string,
|
|
260
|
-
warnings: string[],
|
|
261
|
-
): void {
|
|
262
|
-
const enumValue = readProperty(schema, "enum");
|
|
263
|
-
if (Array.isArray(enumValue) && enumValue.length > 0 && !enumMatches(value, enumValue)) {
|
|
264
|
-
warnings.push(
|
|
265
|
-
`Tool call "${toolName}" ${pathLabel(path)} expected one of ${formatJsonValue(
|
|
266
|
-
enumValue,
|
|
267
|
-
)} but got ${formatJsonValue(value)}.`,
|
|
268
|
-
);
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
const constDescriptor = Object.getOwnPropertyDescriptor(schema, "const");
|
|
272
|
-
if (constDescriptor !== undefined && !jsonValuesEqual(value, constDescriptor.value)) {
|
|
273
|
-
warnings.push(
|
|
274
|
-
`Tool call "${toolName}" ${pathLabel(path)} expected ${formatJsonValue(
|
|
275
|
-
constDescriptor.value,
|
|
276
|
-
)} but got ${formatJsonValue(value)}.`,
|
|
277
|
-
);
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
function validateValueAgainstSchema(
|
|
282
|
-
schema: unknown,
|
|
283
|
-
value: unknown,
|
|
284
|
-
toolName: string,
|
|
285
|
-
path: string,
|
|
286
|
-
warnings: string[],
|
|
287
|
-
): void {
|
|
288
|
-
if (!isRecord(schema)) return;
|
|
289
|
-
|
|
290
|
-
const expectedTypes = schemaTypes(schema);
|
|
291
|
-
if (expectedTypes.length > 0 && !matchesAnyExpectedType(value, expectedTypes)) {
|
|
292
|
-
addTypeWarning(warnings, toolName, path, expectedTypes, value);
|
|
293
|
-
return;
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
validateEnum(schema, value, toolName, path, warnings);
|
|
297
|
-
|
|
298
|
-
if (schemaAllowsObjectValidation(schema, expectedTypes)) {
|
|
299
|
-
if (isRecord(value)) {
|
|
300
|
-
validateObjectSchema(schema, value, toolName, path, warnings);
|
|
301
|
-
} else if (expectedTypes.length === 0) {
|
|
302
|
-
warnings.push(
|
|
303
|
-
`Tool call "${toolName}" ${pathLabel(path)} expected object but got ${actualType(value)}.`,
|
|
304
|
-
);
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
if (schemaAllowsArrayValidation(schema, expectedTypes)) {
|
|
309
|
-
if (Array.isArray(value)) {
|
|
310
|
-
validateArraySchema(schema, value, toolName, path, warnings);
|
|
311
|
-
} else if (expectedTypes.length === 0) {
|
|
312
|
-
warnings.push(
|
|
313
|
-
`Tool call "${toolName}" ${pathLabel(path)} expected array but got ${actualType(value)}.`,
|
|
314
|
-
);
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
function extractAnthropicToolSchemas(request: unknown): Map<string, ToolSchema> {
|
|
320
|
-
const tools = new Map<string, ToolSchema>();
|
|
321
|
-
for (const tool of readArray(request, "tools")) {
|
|
322
|
-
if (!isRecord(tool)) continue;
|
|
323
|
-
const name = readString(tool, "name");
|
|
324
|
-
if (name === null || name === "") continue;
|
|
325
|
-
tools.set(name, {
|
|
326
|
-
name,
|
|
327
|
-
schema: readObject(tool, "input_schema"),
|
|
328
|
-
});
|
|
329
|
-
}
|
|
330
|
-
return tools;
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
function extractOpenAIToolSchemas(request: unknown): Map<string, ToolSchema> {
|
|
334
|
-
const tools = new Map<string, ToolSchema>();
|
|
335
|
-
for (const tool of readArray(request, "tools")) {
|
|
336
|
-
const functionDefinition = readObject(tool, "function");
|
|
337
|
-
const name =
|
|
338
|
-
functionDefinition === null
|
|
339
|
-
? readString(tool, "name")
|
|
340
|
-
: (readString(functionDefinition, "name") ?? readString(tool, "name"));
|
|
341
|
-
if (name === null || name === "") continue;
|
|
342
|
-
const parameters =
|
|
343
|
-
functionDefinition === null
|
|
344
|
-
? readObject(tool, "parameters")
|
|
345
|
-
: (readObject(functionDefinition, "parameters") ?? readObject(tool, "parameters"));
|
|
346
|
-
tools.set(name, {
|
|
347
|
-
name,
|
|
348
|
-
schema: parameters,
|
|
349
|
-
});
|
|
350
|
-
}
|
|
351
|
-
return tools;
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
function mergeToolSchemas(
|
|
355
|
-
primary: Map<string, ToolSchema>,
|
|
356
|
-
secondary: Map<string, ToolSchema>,
|
|
357
|
-
): Map<string, ToolSchema> {
|
|
358
|
-
const merged = new Map(primary);
|
|
359
|
-
for (const [name, schema] of secondary) {
|
|
360
|
-
if (!merged.has(name)) merged.set(name, schema);
|
|
361
|
-
}
|
|
362
|
-
return merged;
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
function extractToolSchemas(request: unknown, apiFormat: ApiFormat): Map<string, ToolSchema> {
|
|
366
|
-
switch (apiFormat) {
|
|
367
|
-
case "anthropic":
|
|
368
|
-
return extractAnthropicToolSchemas(request);
|
|
369
|
-
case "openai":
|
|
370
|
-
return extractOpenAIToolSchemas(request);
|
|
371
|
-
case "unknown":
|
|
372
|
-
return mergeToolSchemas(
|
|
373
|
-
extractOpenAIToolSchemas(request),
|
|
374
|
-
extractAnthropicToolSchemas(request),
|
|
375
|
-
);
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
function parseOpenAIArguments(argumentsValue: unknown): { value: unknown; issue: string | null } {
|
|
380
|
-
if (argumentsValue === undefined) {
|
|
381
|
-
return { value: {}, issue: "arguments field is missing" };
|
|
382
|
-
}
|
|
383
|
-
if (typeof argumentsValue !== "string") {
|
|
384
|
-
return { value: argumentsValue, issue: null };
|
|
385
|
-
}
|
|
386
|
-
try {
|
|
387
|
-
return { value: JSON.parse(argumentsValue), issue: null };
|
|
388
|
-
} catch {
|
|
389
|
-
return { value: {}, issue: "arguments are not valid JSON" };
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
function extractOpenAIToolCalls(response: unknown): ToolCall[] {
|
|
394
|
-
const calls: ToolCall[] = [];
|
|
395
|
-
let choiceIndex = 0;
|
|
396
|
-
for (const choice of readArray(response, "choices")) {
|
|
397
|
-
const message = readObject(choice, "message");
|
|
398
|
-
if (message === null) {
|
|
399
|
-
choiceIndex++;
|
|
400
|
-
continue;
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
let callIndex = 0;
|
|
404
|
-
for (const call of readArray(message, "tool_calls")) {
|
|
405
|
-
const functionCall = readObject(call, "function");
|
|
406
|
-
const name = functionCall === null ? null : readString(functionCall, "name");
|
|
407
|
-
const parsedArguments =
|
|
408
|
-
functionCall === null
|
|
409
|
-
? { value: {}, issue: "function block is missing" }
|
|
410
|
-
: parseOpenAIArguments(readProperty(functionCall, "arguments"));
|
|
411
|
-
calls.push({
|
|
412
|
-
name,
|
|
413
|
-
arguments: parsedArguments.value,
|
|
414
|
-
argumentIssue: parsedArguments.issue,
|
|
415
|
-
location: `choices[${choiceIndex}].message.tool_calls[${callIndex}]`,
|
|
416
|
-
});
|
|
417
|
-
callIndex++;
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
const legacyFunctionCall = readObject(message, "function_call");
|
|
421
|
-
if (legacyFunctionCall !== null) {
|
|
422
|
-
const parsedArguments = parseOpenAIArguments(readProperty(legacyFunctionCall, "arguments"));
|
|
423
|
-
calls.push({
|
|
424
|
-
name: readString(legacyFunctionCall, "name"),
|
|
425
|
-
arguments: parsedArguments.value,
|
|
426
|
-
argumentIssue: parsedArguments.issue,
|
|
427
|
-
location: `choices[${choiceIndex}].message.function_call`,
|
|
428
|
-
});
|
|
429
|
-
}
|
|
430
|
-
choiceIndex++;
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
let outputIndex = 0;
|
|
434
|
-
for (const item of readArray(response, "output")) {
|
|
435
|
-
if (readString(item, "type") !== "function_call") {
|
|
436
|
-
outputIndex++;
|
|
437
|
-
continue;
|
|
438
|
-
}
|
|
439
|
-
const parsedArguments = parseOpenAIArguments(readProperty(item, "arguments"));
|
|
440
|
-
calls.push({
|
|
441
|
-
name: readString(item, "name"),
|
|
442
|
-
arguments: parsedArguments.value,
|
|
443
|
-
argumentIssue: parsedArguments.issue,
|
|
444
|
-
location: `output[${outputIndex}]`,
|
|
445
|
-
});
|
|
446
|
-
outputIndex++;
|
|
447
|
-
}
|
|
448
|
-
return calls;
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
function extractAnthropicToolCalls(response: unknown): ToolCall[] {
|
|
452
|
-
const calls: ToolCall[] = [];
|
|
453
|
-
let contentIndex = 0;
|
|
454
|
-
for (const block of readArray(response, "content")) {
|
|
455
|
-
if (readString(block, "type") !== "tool_use") {
|
|
456
|
-
contentIndex++;
|
|
457
|
-
continue;
|
|
458
|
-
}
|
|
459
|
-
calls.push({
|
|
460
|
-
name: readString(block, "name"),
|
|
461
|
-
arguments: readProperty(block, "input") ?? {},
|
|
462
|
-
argumentIssue: null,
|
|
463
|
-
location: `content[${contentIndex}]`,
|
|
464
|
-
});
|
|
465
|
-
contentIndex++;
|
|
466
|
-
}
|
|
467
|
-
return calls;
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
function extractToolCalls(response: unknown, apiFormat: ApiFormat): ToolCall[] {
|
|
471
|
-
switch (apiFormat) {
|
|
472
|
-
case "anthropic":
|
|
473
|
-
return extractAnthropicToolCalls(response);
|
|
474
|
-
case "openai":
|
|
475
|
-
return extractOpenAIToolCalls(response);
|
|
476
|
-
case "unknown":
|
|
477
|
-
return [...extractOpenAIToolCalls(response), ...extractAnthropicToolCalls(response)];
|
|
478
|
-
}
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
function uniqueWarnings(warnings: readonly string[]): string[] {
|
|
482
|
-
const seen = new Set<string>();
|
|
483
|
-
const unique: string[] = [];
|
|
484
|
-
for (const warning of warnings) {
|
|
485
|
-
if (seen.has(warning)) continue;
|
|
486
|
-
seen.add(warning);
|
|
487
|
-
unique.push(warning);
|
|
488
|
-
}
|
|
489
|
-
return unique;
|
|
490
|
-
}
|
|
491
|
-
|
|
492
|
-
export function analyzeToolSchemaWarnings(input: ToolSchemaWarningInput): string[] {
|
|
493
|
-
const request = parseJson(input.rawRequestBody);
|
|
494
|
-
const response = parseJson(input.responseText);
|
|
495
|
-
if (!request.ok || !response.ok) return [];
|
|
496
|
-
|
|
497
|
-
const toolSchemas = extractToolSchemas(request.value, input.apiFormat);
|
|
498
|
-
const toolCalls = extractToolCalls(response.value, input.apiFormat);
|
|
499
|
-
if (toolCalls.length === 0) return [];
|
|
500
|
-
|
|
501
|
-
const warnings: string[] = [];
|
|
502
|
-
for (const call of toolCalls) {
|
|
503
|
-
if (call.name === null || call.name === "") {
|
|
504
|
-
warnings.push(`Tool call at ${call.location} is missing a tool name.`);
|
|
505
|
-
continue;
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
const schema = toolSchemas.get(call.name);
|
|
509
|
-
if (schema === undefined) {
|
|
510
|
-
warnings.push(
|
|
511
|
-
toolSchemas.size === 0
|
|
512
|
-
? `Tool call "${call.name}" was returned, but the request did not define any tools.`
|
|
513
|
-
: `Tool call "${call.name}" was returned, but it is not defined in the request tools.`,
|
|
514
|
-
);
|
|
515
|
-
continue;
|
|
516
|
-
}
|
|
517
|
-
|
|
518
|
-
if (call.argumentIssue !== null) {
|
|
519
|
-
warnings.push(`Tool call "${call.name}" ${call.argumentIssue}.`);
|
|
520
|
-
continue;
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
if (schema.schema !== null) {
|
|
524
|
-
validateValueAgainstSchema(schema.schema, call.arguments, schema.name, "", warnings);
|
|
525
|
-
}
|
|
526
|
-
}
|
|
527
|
-
|
|
528
|
-
return uniqueWarnings(warnings);
|
|
529
|
-
}
|
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
import { Buffer } from "node:buffer";
|
|
2
|
-
import { readFile } from "node:fs/promises";
|
|
3
|
-
import { extname, relative, resolve, sep } from "node:path";
|
|
4
|
-
|
|
5
|
-
const CONTENT_TYPES: Readonly<Record<string, string>> = {
|
|
6
|
-
".css": "text/css; charset=utf-8",
|
|
7
|
-
".html": "text/html; charset=utf-8",
|
|
8
|
-
".ico": "image/x-icon",
|
|
9
|
-
".jpeg": "image/jpeg",
|
|
10
|
-
".jpg": "image/jpeg",
|
|
11
|
-
".js": "text/javascript; charset=utf-8",
|
|
12
|
-
".json": "application/json; charset=utf-8",
|
|
13
|
-
".map": "application/json; charset=utf-8",
|
|
14
|
-
".png": "image/png",
|
|
15
|
-
".svg": "image/svg+xml",
|
|
16
|
-
".webp": "image/webp",
|
|
17
|
-
".woff": "font/woff",
|
|
18
|
-
".woff2": "font/woff2",
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
export type UiAsset = {
|
|
22
|
-
body: Buffer;
|
|
23
|
-
cacheControl: string;
|
|
24
|
-
contentType: string;
|
|
25
|
-
document: boolean;
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
function safeDecodedPath(pathname: string): string | null {
|
|
29
|
-
let decoded: string;
|
|
30
|
-
try {
|
|
31
|
-
decoded = decodeURIComponent(pathname);
|
|
32
|
-
} catch {
|
|
33
|
-
return null;
|
|
34
|
-
}
|
|
35
|
-
if (decoded.includes("\\") || decoded.includes("\0")) return null;
|
|
36
|
-
if (decoded.split("/").some((segment) => segment === "." || segment === "..")) return null;
|
|
37
|
-
return decoded;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
function isInsideDirectory(path: string, directory: string): boolean {
|
|
41
|
-
const child = relative(directory, path);
|
|
42
|
-
return child === "" || (!child.startsWith("..") && !child.startsWith(sep));
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
function assetPath(uiDirectory: string, pathname: string): string | null {
|
|
46
|
-
const decoded = safeDecodedPath(pathname);
|
|
47
|
-
if (decoded === null) return null;
|
|
48
|
-
const target = resolve(uiDirectory, `.${decoded}`);
|
|
49
|
-
return isInsideDirectory(target, resolve(uiDirectory)) ? target : null;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
async function readAsset(path: string): Promise<Buffer | null> {
|
|
53
|
-
try {
|
|
54
|
-
return await readFile(path);
|
|
55
|
-
} catch {
|
|
56
|
-
return null;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
function contentTypeFor(path: string): string {
|
|
61
|
-
return CONTENT_TYPES[extname(path).toLowerCase()] ?? "application/octet-stream";
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
function isBackendNamespace(pathname: string): boolean {
|
|
65
|
-
return (
|
|
66
|
-
pathname === "/api" ||
|
|
67
|
-
pathname.startsWith("/api/") ||
|
|
68
|
-
pathname === "/proxy" ||
|
|
69
|
-
pathname.startsWith("/proxy/") ||
|
|
70
|
-
pathname === "/livez" ||
|
|
71
|
-
pathname === "/readyz"
|
|
72
|
-
);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
function shouldUseDocumentFallback(pathname: string): boolean {
|
|
76
|
-
if (pathname === "/" || pathname.length === 0) return true;
|
|
77
|
-
const lastSegment = pathname.split("/").at(-1) ?? "";
|
|
78
|
-
return !lastSegment.includes(".");
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
export async function loadUiAsset(uiDirectory: string, pathname: string): Promise<UiAsset | null> {
|
|
82
|
-
if (isBackendNamespace(pathname)) return null;
|
|
83
|
-
const requestedPath = assetPath(uiDirectory, pathname);
|
|
84
|
-
if (requestedPath === null) return null;
|
|
85
|
-
const requestedBody = await readAsset(requestedPath);
|
|
86
|
-
if (requestedBody !== null) {
|
|
87
|
-
return {
|
|
88
|
-
body: requestedBody,
|
|
89
|
-
cacheControl: pathname.startsWith("/assets/")
|
|
90
|
-
? "public, max-age=31536000, immutable"
|
|
91
|
-
: "no-cache",
|
|
92
|
-
contentType: contentTypeFor(requestedPath),
|
|
93
|
-
document: extname(requestedPath).toLowerCase() === ".html",
|
|
94
|
-
};
|
|
95
|
-
}
|
|
96
|
-
if (!shouldUseDocumentFallback(pathname)) return null;
|
|
97
|
-
const indexPath = resolve(uiDirectory, "index.html");
|
|
98
|
-
const indexBody = await readAsset(indexPath);
|
|
99
|
-
if (indexBody === null) return null;
|
|
100
|
-
return {
|
|
101
|
-
body: indexBody,
|
|
102
|
-
cacheControl: "no-store",
|
|
103
|
-
contentType: CONTENT_TYPES[".html"] ?? "text/html; charset=utf-8",
|
|
104
|
-
document: true,
|
|
105
|
-
};
|
|
106
|
-
}
|