@tonyclaw/agent-inspector 2.0.0
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/cli.js +1611 -0
- package/.output/nitro.json +17 -0
- package/.output/public/assets/CompareDrawer-CU5ZrWcL.js +1 -0
- package/.output/public/assets/ProxyViewerContainer-pEBqVp1d.js +101 -0
- package/.output/public/assets/ReplayDialog-F58yNg5j.js +1 -0
- package/.output/public/assets/RequestAnatomy-C9lT0qE_.js +1 -0
- package/.output/public/assets/ResponseView-DHJq6bnz.js +1 -0
- package/.output/public/assets/StreamingChunkSequence-BTgfpFUT.js +1 -0
- package/.output/public/assets/_sessionId-DsNRbnNm.js +1 -0
- package/.output/public/assets/alibaba-TTwafVwX.svg +1 -0
- package/.output/public/assets/index-CpWG2hFn.css +1 -0
- package/.output/public/assets/index-DmBV8Gve.js +1 -0
- package/.output/public/assets/json-viewer-CZVYLR8j.js +14 -0
- package/.output/public/assets/main-DHs7FBK3.js +18 -0
- package/.output/public/assets/minimax-BPMzvuL-.jpeg +0 -0
- package/.output/public/assets/qwen-CONDcHqt.png +0 -0
- package/.output/public/assets/zhipuai-BPNAnxo-.svg +219 -0
- package/.output/server/_chunks/ssr-renderer.mjs +22 -0
- package/.output/server/_libs/@radix-ui/react-accessible-icon+[...].mjs +1 -0
- package/.output/server/_libs/@radix-ui/react-dismissable-layer+[...].mjs +210 -0
- package/.output/server/_libs/@radix-ui/react-navigation-menu+[...].mjs +2 -0
- package/.output/server/_libs/@radix-ui/react-one-time-password-field+[...].mjs +2 -0
- package/.output/server/_libs/@radix-ui/react-password-toggle-field+[...].mjs +2 -0
- package/.output/server/_libs/@radix-ui/react-use-callback-ref+[...].mjs +11 -0
- package/.output/server/_libs/@radix-ui/react-use-controllable-state+[...].mjs +69 -0
- package/.output/server/_libs/@radix-ui/react-use-effect-event+[...].mjs +1 -0
- package/.output/server/_libs/@radix-ui/react-use-escape-keydown+[...].mjs +17 -0
- package/.output/server/_libs/@radix-ui/react-use-is-hydrated+[...].mjs +1 -0
- package/.output/server/_libs/@radix-ui/react-use-layout-effect+[...].mjs +6 -0
- package/.output/server/_libs/@radix-ui/react-visually-hidden+[...].mjs +34 -0
- package/.output/server/_libs/ajv-formats.mjs +330 -0
- package/.output/server/_libs/ajv.mjs +11444 -0
- package/.output/server/_libs/aria-hidden.mjs +122 -0
- package/.output/server/_libs/atomically.mjs +152 -0
- package/.output/server/_libs/bail.mjs +8 -0
- package/.output/server/_libs/cfworker__json-schema.mjs +1 -0
- package/.output/server/_libs/character-entities.mjs +2130 -0
- package/.output/server/_libs/class-variance-authority.mjs +44 -0
- package/.output/server/_libs/clsx.mjs +16 -0
- package/.output/server/_libs/comma-separated-tokens.mjs +10 -0
- package/.output/server/_libs/conf.mjs +635 -0
- package/.output/server/_libs/cookie-es.mjs +58 -0
- package/.output/server/_libs/core-util-is.mjs +75 -0
- package/.output/server/_libs/croner.mjs +1 -0
- package/.output/server/_libs/crossws.mjs +1 -0
- package/.output/server/_libs/debounce-fn.mjs +69 -0
- package/.output/server/_libs/decode-named-character-reference+[...].mjs +8 -0
- package/.output/server/_libs/dequal.mjs +27 -0
- package/.output/server/_libs/detect-node-es.mjs +1 -0
- package/.output/server/_libs/devlop.mjs +8 -0
- package/.output/server/_libs/diff.mjs +320 -0
- package/.output/server/_libs/dot-prop.mjs +265 -0
- package/.output/server/_libs/env-paths.mjs +57 -0
- package/.output/server/_libs/estree-util-is-identifier-name.mjs +11 -0
- package/.output/server/_libs/extend.mjs +97 -0
- package/.output/server/_libs/fast-deep-equal.mjs +38 -0
- package/.output/server/_libs/fast-uri.mjs +812 -0
- package/.output/server/_libs/floating-ui__core.mjs +725 -0
- package/.output/server/_libs/floating-ui__dom.mjs +622 -0
- package/.output/server/_libs/floating-ui__react-dom.mjs +292 -0
- package/.output/server/_libs/floating-ui__utils.mjs +320 -0
- package/.output/server/_libs/get-nonce.mjs +9 -0
- package/.output/server/_libs/h3-v2.mjs +276 -0
- package/.output/server/_libs/h3.mjs +408 -0
- package/.output/server/_libs/hast-util-to-jsx-runtime.mjs +388 -0
- package/.output/server/_libs/hast-util-whitespace.mjs +10 -0
- package/.output/server/_libs/hookable.mjs +1 -0
- package/.output/server/_libs/html-url-attributes.mjs +26 -0
- package/.output/server/_libs/immediate.mjs +74 -0
- package/.output/server/_libs/inherits.mjs +50 -0
- package/.output/server/_libs/inline-style-parser.mjs +142 -0
- package/.output/server/_libs/is-plain-obj.mjs +10 -0
- package/.output/server/_libs/isarray.mjs +14 -0
- package/.output/server/_libs/isbot.mjs +20 -0
- package/.output/server/_libs/json-schema-traverse.mjs +180 -0
- package/.output/server/_libs/jszip.mjs +3051 -0
- package/.output/server/_libs/lie.mjs +273 -0
- package/.output/server/_libs/lucide-react.mjs +492 -0
- package/.output/server/_libs/mdast-util-from-markdown.mjs +717 -0
- package/.output/server/_libs/mdast-util-to-hast.mjs +710 -0
- package/.output/server/_libs/mdast-util-to-string.mjs +38 -0
- package/.output/server/_libs/micromark-core-commonmark.mjs +2259 -0
- package/.output/server/_libs/micromark-factory-destination.mjs +94 -0
- package/.output/server/_libs/micromark-factory-label.mjs +63 -0
- package/.output/server/_libs/micromark-factory-space.mjs +24 -0
- package/.output/server/_libs/micromark-factory-title.mjs +65 -0
- package/.output/server/_libs/micromark-factory-whitespace.mjs +22 -0
- package/.output/server/_libs/micromark-util-character.mjs +44 -0
- package/.output/server/_libs/micromark-util-chunked.mjs +36 -0
- package/.output/server/_libs/micromark-util-classify-character+[...].mjs +12 -0
- package/.output/server/_libs/micromark-util-combine-extensions+[...].mjs +41 -0
- package/.output/server/_libs/micromark-util-decode-numeric-character-reference+[...].mjs +19 -0
- package/.output/server/_libs/micromark-util-decode-string.mjs +21 -0
- package/.output/server/_libs/micromark-util-encode.mjs +1 -0
- package/.output/server/_libs/micromark-util-html-tag-name.mjs +69 -0
- package/.output/server/_libs/micromark-util-normalize-identifier+[...].mjs +6 -0
- package/.output/server/_libs/micromark-util-resolve-all.mjs +15 -0
- package/.output/server/_libs/micromark-util-sanitize-uri.mjs +41 -0
- package/.output/server/_libs/micromark-util-subtokenize.mjs +346 -0
- package/.output/server/_libs/micromark.mjs +906 -0
- package/.output/server/_libs/mimic-function.mjs +47 -0
- package/.output/server/_libs/modelcontextprotocol__server.mjs +9738 -0
- package/.output/server/_libs/ocache.mjs +1 -0
- package/.output/server/_libs/ohash.mjs +1 -0
- package/.output/server/_libs/pako.mjs +4223 -0
- package/.output/server/_libs/process-nextick-args.mjs +48 -0
- package/.output/server/_libs/property-information.mjs +1209 -0
- package/.output/server/_libs/radix-ui.mjs +1 -0
- package/.output/server/_libs/radix-ui__number.mjs +6 -0
- package/.output/server/_libs/radix-ui__primitive.mjs +11 -0
- package/.output/server/_libs/radix-ui__react-accordion.mjs +1 -0
- package/.output/server/_libs/radix-ui__react-alert-dialog.mjs +1 -0
- package/.output/server/_libs/radix-ui__react-arrow.mjs +23 -0
- package/.output/server/_libs/radix-ui__react-aspect-ratio.mjs +1 -0
- package/.output/server/_libs/radix-ui__react-avatar.mjs +1 -0
- package/.output/server/_libs/radix-ui__react-checkbox.mjs +1 -0
- package/.output/server/_libs/radix-ui__react-collapsible.mjs +144 -0
- package/.output/server/_libs/radix-ui__react-collection.mjs +69 -0
- package/.output/server/_libs/radix-ui__react-compose-refs.mjs +39 -0
- package/.output/server/_libs/radix-ui__react-context-menu.mjs +1 -0
- package/.output/server/_libs/radix-ui__react-context.mjs +78 -0
- package/.output/server/_libs/radix-ui__react-dialog.mjs +325 -0
- package/.output/server/_libs/radix-ui__react-direction.mjs +9 -0
- package/.output/server/_libs/radix-ui__react-dropdown-menu.mjs +1 -0
- package/.output/server/_libs/radix-ui__react-focus-guards.mjs +29 -0
- package/.output/server/_libs/radix-ui__react-focus-scope.mjs +206 -0
- package/.output/server/_libs/radix-ui__react-form.mjs +1 -0
- package/.output/server/_libs/radix-ui__react-hover-card.mjs +1 -0
- package/.output/server/_libs/radix-ui__react-id.mjs +14 -0
- package/.output/server/_libs/radix-ui__react-label.mjs +1 -0
- package/.output/server/_libs/radix-ui__react-menu.mjs +1 -0
- package/.output/server/_libs/radix-ui__react-menubar.mjs +1 -0
- package/.output/server/_libs/radix-ui__react-popover.mjs +1 -0
- package/.output/server/_libs/radix-ui__react-popper.mjs +286 -0
- package/.output/server/_libs/radix-ui__react-portal.mjs +16 -0
- package/.output/server/_libs/radix-ui__react-presence.mjs +128 -0
- package/.output/server/_libs/radix-ui__react-primitive.mjs +42 -0
- package/.output/server/_libs/radix-ui__react-progress.mjs +1 -0
- package/.output/server/_libs/radix-ui__react-radio-group.mjs +1 -0
- package/.output/server/_libs/radix-ui__react-roving-focus.mjs +224 -0
- package/.output/server/_libs/radix-ui__react-scroll-area.mjs +721 -0
- package/.output/server/_libs/radix-ui__react-select.mjs +1163 -0
- package/.output/server/_libs/radix-ui__react-separator.mjs +28 -0
- package/.output/server/_libs/radix-ui__react-slider.mjs +1 -0
- package/.output/server/_libs/radix-ui__react-slot.mjs +99 -0
- package/.output/server/_libs/radix-ui__react-switch.mjs +1 -0
- package/.output/server/_libs/radix-ui__react-tabs.mjs +189 -0
- package/.output/server/_libs/radix-ui__react-toast.mjs +2 -0
- package/.output/server/_libs/radix-ui__react-toggle-group.mjs +1 -0
- package/.output/server/_libs/radix-ui__react-toggle.mjs +1 -0
- package/.output/server/_libs/radix-ui__react-toolbar.mjs +1 -0
- package/.output/server/_libs/radix-ui__react-tooltip.mjs +495 -0
- package/.output/server/_libs/radix-ui__react-use-previous.mjs +14 -0
- package/.output/server/_libs/radix-ui__react-use-size.mjs +39 -0
- package/.output/server/_libs/react-dom.mjs +10781 -0
- package/.output/server/_libs/react-markdown.mjs +147 -0
- package/.output/server/_libs/react-remove-scroll-bar.mjs +82 -0
- package/.output/server/_libs/react-remove-scroll.mjs +328 -0
- package/.output/server/_libs/react-style-singleton.mjs +69 -0
- package/.output/server/_libs/react.mjs +515 -0
- package/.output/server/_libs/readable-stream.mjs +1518 -0
- package/.output/server/_libs/remark-parse.mjs +19 -0
- package/.output/server/_libs/remark-rehype.mjs +21 -0
- package/.output/server/_libs/rou3.mjs +14 -0
- package/.output/server/_libs/safe-buffer.mjs +64 -0
- package/.output/server/_libs/semver.mjs +1938 -0
- package/.output/server/_libs/seroval-plugins.mjs +58 -0
- package/.output/server/_libs/seroval.mjs +1765 -0
- package/.output/server/_libs/setimmediate.mjs +152 -0
- package/.output/server/_libs/space-separated-tokens.mjs +6 -0
- package/.output/server/_libs/srvx.mjs +1029 -0
- package/.output/server/_libs/stubborn-fs.mjs +91 -0
- package/.output/server/_libs/stubborn-utils.mjs +66 -0
- package/.output/server/_libs/style-to-js.mjs +72 -0
- package/.output/server/_libs/style-to-object.mjs +38 -0
- package/.output/server/_libs/swr.mjs +939 -0
- package/.output/server/_libs/tailwind-merge.mjs +3010 -0
- package/.output/server/_libs/tanstack__history.mjs +217 -0
- package/.output/server/_libs/tanstack__react-router.mjs +1480 -0
- package/.output/server/_libs/tanstack__react-store.mjs +1 -0
- package/.output/server/_libs/tanstack__react-virtual.mjs +44 -0
- package/.output/server/_libs/tanstack__router-core.mjs +4827 -0
- package/.output/server/_libs/tanstack__store.mjs +1 -0
- package/.output/server/_libs/tanstack__virtual-core.mjs +1225 -0
- package/.output/server/_libs/tiny-invariant.mjs +12 -0
- package/.output/server/_libs/tiny-warning.mjs +5 -0
- package/.output/server/_libs/trim-lines.mjs +41 -0
- package/.output/server/_libs/trough.mjs +85 -0
- package/.output/server/_libs/tslib.mjs +1 -0
- package/.output/server/_libs/ufo.mjs +54 -0
- package/.output/server/_libs/uint8array-extras.mjs +69 -0
- package/.output/server/_libs/ungap__structured-clone.mjs +212 -0
- package/.output/server/_libs/unified.mjs +661 -0
- package/.output/server/_libs/unist-util-is.mjs +100 -0
- package/.output/server/_libs/unist-util-position.mjs +27 -0
- package/.output/server/_libs/unist-util-stringify-position.mjs +27 -0
- package/.output/server/_libs/unist-util-visit-parents.mjs +82 -0
- package/.output/server/_libs/unist-util-visit.mjs +24 -0
- package/.output/server/_libs/unstorage.mjs +1 -0
- package/.output/server/_libs/use-callback-ref.mjs +66 -0
- package/.output/server/_libs/use-sidecar.mjs +106 -0
- package/.output/server/_libs/use-sync-external-store.mjs +64 -0
- package/.output/server/_libs/util-deprecate.mjs +12 -0
- package/.output/server/_libs/vfile-message.mjs +138 -0
- package/.output/server/_libs/vfile.mjs +467 -0
- package/.output/server/_libs/when-exit.mjs +53 -0
- package/.output/server/_libs/zod.mjs +4524 -0
- package/.output/server/_sessionId-wMLPvC5g.mjs +123 -0
- package/.output/server/_ssr/CompareDrawer-BU4V0uVf.mjs +1041 -0
- package/.output/server/_ssr/ProxyViewerContainer-BnRwFEnn.mjs +5972 -0
- package/.output/server/_ssr/ReplayDialog-C7dn9pd_.mjs +322 -0
- package/.output/server/_ssr/RequestAnatomy-C1rWpe9-.mjs +353 -0
- package/.output/server/_ssr/ResponseView-hGpPaYsf.mjs +602 -0
- package/.output/server/_ssr/StreamingChunkSequence-BRWI1r_G.mjs +302 -0
- package/.output/server/_ssr/index-BKURLVPz.mjs +118 -0
- package/.output/server/_ssr/index.mjs +1184 -0
- package/.output/server/_ssr/json-viewer-BBd2DtQP.mjs +515 -0
- package/.output/server/_ssr/router-BcZ0D6AB.mjs +6317 -0
- package/.output/server/_ssr/start-HYkvq4Ni.mjs +4 -0
- package/.output/server/_tanstack-start-manifest_v-1y8ZVxRI.mjs +4 -0
- package/.output/server/index.mjs +436 -0
- package/.output/server/node_modules/tslib/modules/index.js +70 -0
- package/.output/server/node_modules/tslib/modules/package.json +3 -0
- package/.output/server/node_modules/tslib/package.json +47 -0
- package/.output/server/node_modules/tslib/tslib.js +484 -0
- package/.output/server/package.json +9 -0
- package/LICENSE +21 -0
- package/README.md +52 -0
- package/package.json +110 -0
- package/src/assets/favicon.svg +31 -0
- package/src/assets/logos/alibaba.svg +1 -0
- package/src/assets/logos/anthropic.svg +1 -0
- package/src/assets/logos/claude-code.svg +4 -0
- package/src/assets/logos/deepseek.svg +1 -0
- package/src/assets/logos/mcp.png +0 -0
- package/src/assets/logos/minimax.jpeg +0 -0
- package/src/assets/logos/openai.svg +1 -0
- package/src/assets/logos/opencode.svg +4 -0
- package/src/assets/logos/qwen.png +0 -0
- package/src/assets/logos/zhipuai.svg +219 -0
- package/src/cli/detect-tools.ts +147 -0
- package/src/cli/doctor.ts +521 -0
- package/src/cli/onboard.ts +224 -0
- package/src/cli/templates/command-onboard.ts +17 -0
- package/src/cli/templates/skill-onboard.ts +547 -0
- package/src/cli.ts +345 -0
- package/src/components/OnboardingBanner.tsx +67 -0
- package/src/components/ProxyViewer.tsx +545 -0
- package/src/components/ProxyViewerContainer.tsx +363 -0
- package/src/components/providers/ImportWizardDialog.tsx +349 -0
- package/src/components/providers/ProviderCard.tsx +474 -0
- package/src/components/providers/ProviderForm.tsx +494 -0
- package/src/components/providers/ProviderLogo.tsx +117 -0
- package/src/components/providers/ProvidersPanel.tsx +619 -0
- package/src/components/providers/SettingsDialog.tsx +202 -0
- package/src/components/proxy-viewer/CompareDrawer.tsx +893 -0
- package/src/components/proxy-viewer/ConversationGroup.tsx +107 -0
- package/src/components/proxy-viewer/ConversationHeader.tsx +300 -0
- package/src/components/proxy-viewer/LogEntry.tsx +543 -0
- package/src/components/proxy-viewer/LogEntryHeader.tsx +501 -0
- package/src/components/proxy-viewer/ReplayDialog.tsx +218 -0
- package/src/components/proxy-viewer/ResponseView.tsx +171 -0
- package/src/components/proxy-viewer/StreamingChunkSequence.tsx +188 -0
- package/src/components/proxy-viewer/ThreadConnector.tsx +136 -0
- package/src/components/proxy-viewer/TurnGroup.tsx +337 -0
- package/src/components/proxy-viewer/anatomy/RequestAnatomy.tsx +98 -0
- package/src/components/proxy-viewer/anatomy/SegmentBar.tsx +196 -0
- package/src/components/proxy-viewer/anatomy/tokenEstimate.ts +53 -0
- package/src/components/proxy-viewer/anatomy/types.ts +39 -0
- package/src/components/proxy-viewer/anatomy/useAnatomyJump.ts +114 -0
- package/src/components/proxy-viewer/cacheTrend.ts +50 -0
- package/src/components/proxy-viewer/diff/DiffView.tsx +321 -0
- package/src/components/proxy-viewer/diff/computeDiff.ts +178 -0
- package/src/components/proxy-viewer/diff/index.ts +3 -0
- package/src/components/proxy-viewer/formats/anthropic/ContentBlocks.tsx +157 -0
- package/src/components/proxy-viewer/formats/anthropic/ResponseView.tsx +66 -0
- package/src/components/proxy-viewer/formats/anthropic/thinkingExtract.ts +21 -0
- package/src/components/proxy-viewer/formats/index.tsx +33 -0
- package/src/components/proxy-viewer/formats/openai/ResponseView.tsx +170 -0
- package/src/components/proxy-viewer/index.ts +9 -0
- package/src/components/proxy-viewer/lazy.ts +37 -0
- package/src/components/proxy-viewer/log-formats/anthropic.ts +194 -0
- package/src/components/proxy-viewer/log-formats/index.ts +23 -0
- package/src/components/proxy-viewer/log-formats/openai.ts +167 -0
- package/src/components/proxy-viewer/log-formats/types.ts +40 -0
- package/src/components/proxy-viewer/log-formats/unknown.ts +18 -0
- package/src/components/proxy-viewer/logEntryVisibility.ts +39 -0
- package/src/components/proxy-viewer/requestDiff.ts +277 -0
- package/src/components/proxy-viewer/useCopyFeedback.ts +36 -0
- package/src/components/proxy-viewer/useKeyboardNavigation.ts +190 -0
- package/src/components/proxy-viewer/viewerState.ts +66 -0
- package/src/components/ui/badge.tsx +47 -0
- package/src/components/ui/button.tsx +47 -0
- package/src/components/ui/collapsible.tsx +21 -0
- package/src/components/ui/confirm-dialog.tsx +51 -0
- package/src/components/ui/crab-logo.tsx +95 -0
- package/src/components/ui/crab-variants.tsx +467 -0
- package/src/components/ui/dialog.tsx +129 -0
- package/src/components/ui/json-expansion-button.tsx +56 -0
- package/src/components/ui/json-viewer-bulk.ts +97 -0
- package/src/components/ui/json-viewer.tsx +494 -0
- package/src/components/ui/mcp-logo.tsx +20 -0
- package/src/components/ui/scroll-area.tsx +54 -0
- package/src/components/ui/select.tsx +178 -0
- package/src/components/ui/separator.tsx +28 -0
- package/src/components/ui/tabs.tsx +88 -0
- package/src/components/ui/tooltip.tsx +51 -0
- package/src/index.css +11 -0
- package/src/knowledge/candidateStore.ts +63 -0
- package/src/knowledge/distiller.ts +98 -0
- package/src/knowledge/openclawClient.ts +118 -0
- package/src/knowledge/redactor.ts +80 -0
- package/src/knowledge/types.ts +84 -0
- package/src/lib/apiClient.ts +49 -0
- package/src/lib/export-logs.ts +51 -0
- package/src/lib/mask.ts +4 -0
- package/src/lib/objectUtils.ts +22 -0
- package/src/lib/providerContract.ts +26 -0
- package/src/lib/providerTestContract.ts +107 -0
- package/src/lib/runtimeConfig.ts +25 -0
- package/src/lib/serverPort.ts +41 -0
- package/src/lib/sessionUrl.ts +44 -0
- package/src/lib/stopReason.ts +58 -0
- package/src/lib/useOnboarding.ts +80 -0
- package/src/lib/useProviders.ts +30 -0
- package/src/lib/useStripConfig.ts +108 -0
- package/src/lib/utils.ts +21 -0
- package/src/mcp/loopback.ts +76 -0
- package/src/mcp/previewExtractor.ts +166 -0
- package/src/mcp/server.ts +396 -0
- package/src/mcp/toolHandlers.ts +341 -0
- package/src/proxy/chunkStorage.ts +112 -0
- package/src/proxy/claudeCodeStrip.ts +99 -0
- package/src/proxy/config.ts +172 -0
- package/src/proxy/constants.ts +47 -0
- package/src/proxy/dataDir.ts +86 -0
- package/src/proxy/formats/anthropic/anthropicProvider.ts +75 -0
- package/src/proxy/formats/anthropic/handler.ts +71 -0
- package/src/proxy/formats/anthropic/index.ts +14 -0
- package/src/proxy/formats/anthropic/register.ts +4 -0
- package/src/proxy/formats/anthropic/schemas.ts +237 -0
- package/src/proxy/formats/anthropic/stream.ts +205 -0
- package/src/proxy/formats/handler.ts +46 -0
- package/src/proxy/formats/index.ts +12 -0
- package/src/proxy/formats/jsonSchema.ts +36 -0
- package/src/proxy/formats/openai/alibabaProvider.ts +38 -0
- package/src/proxy/formats/openai/handler.ts +96 -0
- package/src/proxy/formats/openai/index.ts +25 -0
- package/src/proxy/formats/openai/provider.ts +50 -0
- package/src/proxy/formats/openai/register.ts +4 -0
- package/src/proxy/formats/openai/schemas.ts +187 -0
- package/src/proxy/formats/openai/stream.ts +206 -0
- package/src/proxy/formats/protocol.ts +50 -0
- package/src/proxy/formats/providerRegistry.ts +51 -0
- package/src/proxy/formats/providers/index.ts +3 -0
- package/src/proxy/formats/registry.ts +66 -0
- package/src/proxy/handler.ts +334 -0
- package/src/proxy/logFinalizer.ts +305 -0
- package/src/proxy/logFinalizer.worker.ts +24 -0
- package/src/proxy/logIndex.ts +268 -0
- package/src/proxy/logger.ts +179 -0
- package/src/proxy/openaiOrphanToolStrip.ts +142 -0
- package/src/proxy/providerImporters.ts +491 -0
- package/src/proxy/providers.ts +613 -0
- package/src/proxy/schemas.ts +209 -0
- package/src/proxy/sessionProcess.ts +140 -0
- package/src/proxy/sessionRuntime.ts +85 -0
- package/src/proxy/sessionSupervisor.ts +283 -0
- package/src/proxy/sessionWorkerEntry.ts +26 -0
- package/src/proxy/socketTracker.ts +255 -0
- package/src/proxy/store.ts +412 -0
- package/src/proxy/upstream.ts +90 -0
- package/src/router.tsx +16 -0
- package/src/routes/__root.tsx +45 -0
- package/src/routes/api/config.paths.ts +14 -0
- package/src/routes/api/config.ts +53 -0
- package/src/routes/api/health.ts +15 -0
- package/src/routes/api/knowledge.candidates.$candidateId.promote.ts +32 -0
- package/src/routes/api/knowledge.candidates.ts +10 -0
- package/src/routes/api/knowledge.project-context.ts +18 -0
- package/src/routes/api/knowledge.search.ts +31 -0
- package/src/routes/api/knowledge.sessions.$sessionId.candidates.ts +16 -0
- package/src/routes/api/logs.$id.chunks.ts +36 -0
- package/src/routes/api/logs.$id.replay.ts +191 -0
- package/src/routes/api/logs.$id.ts +22 -0
- package/src/routes/api/logs.stream.ts +74 -0
- package/src/routes/api/logs.ts +59 -0
- package/src/routes/api/mcp.ts +25 -0
- package/src/routes/api/models.ts +10 -0
- package/src/routes/api/providers.$providerId.test.log.ts +293 -0
- package/src/routes/api/providers.$providerId.ts +50 -0
- package/src/routes/api/providers.export.ts +26 -0
- package/src/routes/api/providers.import.ts +47 -0
- package/src/routes/api/providers.scan.ts +23 -0
- package/src/routes/api/providers.ts +45 -0
- package/src/routes/api/sessions.ts +17 -0
- package/src/routes/index.tsx +6 -0
- package/src/routes/proxy/$.ts +15 -0
- package/src/routes/session/$sessionId.tsx +23 -0
- package/styles/globals.css +188 -0
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { JsonValueSchema } from "../jsonSchema";
|
|
3
|
+
|
|
4
|
+
const CacheControl = z.object({
|
|
5
|
+
type: z.string(),
|
|
6
|
+
ttl: z.string().optional(),
|
|
7
|
+
scope: z.string().optional(),
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
const TextContentBlock = z.object({
|
|
11
|
+
type: z.literal("text"),
|
|
12
|
+
text: z.string(),
|
|
13
|
+
cache_control: CacheControl.optional(),
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
const ThinkingContentBlock = z.object({
|
|
17
|
+
type: z.literal("thinking"),
|
|
18
|
+
thinking: z.string(),
|
|
19
|
+
signature: z.string().optional(),
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
const ThinkContentBlock = z.object({
|
|
23
|
+
type: z.literal("think"),
|
|
24
|
+
thinking: z.string(),
|
|
25
|
+
signature: z.string().optional(),
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
const ImageSourceBlock = z.object({
|
|
29
|
+
type: z.literal("base64"),
|
|
30
|
+
media_type: z.string(),
|
|
31
|
+
data: z.string(),
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
const ImageContentBlock = z.object({
|
|
35
|
+
type: z.literal("image"),
|
|
36
|
+
source: ImageSourceBlock,
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
const ToolUseContentBlock = z.object({
|
|
40
|
+
type: z.literal("tool_use"),
|
|
41
|
+
id: z.string(),
|
|
42
|
+
name: z.string(),
|
|
43
|
+
input: z.record(z.string(), JsonValueSchema),
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
const ToolResultContentItem = z.discriminatedUnion("type", [TextContentBlock, ImageContentBlock]);
|
|
47
|
+
|
|
48
|
+
const ToolResultContentBlock = z.object({
|
|
49
|
+
type: z.literal("tool_result"),
|
|
50
|
+
tool_use_id: z.string().optional(),
|
|
51
|
+
content: z.union([z.string(), z.array(ToolResultContentItem)]),
|
|
52
|
+
is_error: z.boolean().optional(),
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
const ContentBlock = z.discriminatedUnion("type", [
|
|
56
|
+
TextContentBlock,
|
|
57
|
+
ThinkingContentBlock,
|
|
58
|
+
ImageContentBlock,
|
|
59
|
+
ToolUseContentBlock,
|
|
60
|
+
ToolResultContentBlock,
|
|
61
|
+
]);
|
|
62
|
+
|
|
63
|
+
const MessageContent = z.union([z.string(), z.array(ContentBlock)]);
|
|
64
|
+
|
|
65
|
+
const Message = z.object({
|
|
66
|
+
role: z.enum(["user", "assistant"]),
|
|
67
|
+
content: MessageContent,
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
const SystemBlock = z.object({
|
|
71
|
+
type: z.literal("text"),
|
|
72
|
+
text: z.string(),
|
|
73
|
+
cache_control: CacheControl.optional(),
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
const InputSchema = z.object({
|
|
77
|
+
type: z.string(),
|
|
78
|
+
properties: z.record(z.string(), z.record(z.string(), JsonValueSchema)).optional(),
|
|
79
|
+
required: z.array(z.string()).optional(),
|
|
80
|
+
additionalProperties: z.boolean().optional(),
|
|
81
|
+
$schema: z.string().optional(),
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
const ToolDefinition = z.object({
|
|
85
|
+
name: z.string(),
|
|
86
|
+
description: z.string().optional(),
|
|
87
|
+
input_schema: InputSchema.optional(),
|
|
88
|
+
cache_control: CacheControl.optional(),
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
const ThinkingConfig = z.discriminatedUnion("type", [
|
|
92
|
+
z.object({ type: z.literal("enabled"), budget_tokens: z.number() }),
|
|
93
|
+
z.object({ type: z.literal("disabled") }),
|
|
94
|
+
z.object({ type: z.literal("adaptive") }),
|
|
95
|
+
]);
|
|
96
|
+
|
|
97
|
+
export const AnthropicRequestSchema = z.object({
|
|
98
|
+
model: z.string(),
|
|
99
|
+
messages: z.array(Message),
|
|
100
|
+
system: z.array(SystemBlock).optional(),
|
|
101
|
+
tools: z.array(ToolDefinition).optional(),
|
|
102
|
+
max_tokens: z.number().optional(),
|
|
103
|
+
temperature: z.number().optional(),
|
|
104
|
+
stream: z.boolean().optional(),
|
|
105
|
+
thinking: ThinkingConfig.optional(),
|
|
106
|
+
metadata: z
|
|
107
|
+
.object({
|
|
108
|
+
user_id: z.string().optional(),
|
|
109
|
+
})
|
|
110
|
+
.optional(),
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
const ResponseContentBlock = z.discriminatedUnion("type", [
|
|
114
|
+
TextContentBlock,
|
|
115
|
+
ThinkingContentBlock,
|
|
116
|
+
ThinkContentBlock,
|
|
117
|
+
ToolUseContentBlock,
|
|
118
|
+
]);
|
|
119
|
+
|
|
120
|
+
const ResponseUsageSchema = z
|
|
121
|
+
.object({
|
|
122
|
+
input_tokens: z.number().nullable().optional(),
|
|
123
|
+
output_tokens: z.number().nullable().optional(),
|
|
124
|
+
cache_creation_input_tokens: z.number().nullable().optional(),
|
|
125
|
+
cache_read_input_tokens: z.number().nullable().optional(),
|
|
126
|
+
})
|
|
127
|
+
.passthrough(); // Allow extra fields from different providers
|
|
128
|
+
|
|
129
|
+
export const AnthropicResponseSchema = z
|
|
130
|
+
.object({
|
|
131
|
+
id: z.string(),
|
|
132
|
+
type: z.literal("message"),
|
|
133
|
+
model: z.string(),
|
|
134
|
+
role: z.literal("assistant"),
|
|
135
|
+
content: z.array(ResponseContentBlock),
|
|
136
|
+
stop_reason: z.string().nullable(),
|
|
137
|
+
stop_sequence: z.string().nullable().optional(),
|
|
138
|
+
usage: ResponseUsageSchema,
|
|
139
|
+
})
|
|
140
|
+
.passthrough(); // Allow extra unknown fields
|
|
141
|
+
|
|
142
|
+
const SseMessageStartEvent = z.object({
|
|
143
|
+
type: z.literal("message_start"),
|
|
144
|
+
message: z.object({
|
|
145
|
+
id: z.string(),
|
|
146
|
+
type: z.literal("message"),
|
|
147
|
+
model: z.string(),
|
|
148
|
+
role: z.literal("assistant"),
|
|
149
|
+
content: z.array(ResponseContentBlock),
|
|
150
|
+
stop_reason: z.null(),
|
|
151
|
+
stop_sequence: z.null(),
|
|
152
|
+
usage: z
|
|
153
|
+
.object({
|
|
154
|
+
input_tokens: z.number(),
|
|
155
|
+
cache_creation_input_tokens: z.number().optional(),
|
|
156
|
+
cache_read_input_tokens: z.number().optional(),
|
|
157
|
+
})
|
|
158
|
+
.passthrough(),
|
|
159
|
+
}),
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
const SseContentBlockStartEvent = z.object({
|
|
163
|
+
type: z.literal("content_block_start"),
|
|
164
|
+
index: z.number(),
|
|
165
|
+
content_block: ResponseContentBlock,
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
const SseDeltaBlock = z.discriminatedUnion("type", [
|
|
169
|
+
z.object({ type: z.literal("text_delta"), text: z.string() }),
|
|
170
|
+
z.object({ type: z.literal("input_json_delta"), partial_json: z.string() }),
|
|
171
|
+
z.object({ type: z.literal("thinking_delta"), thinking: z.string() }),
|
|
172
|
+
z.object({ type: z.literal("signature_delta"), signature: z.string() }),
|
|
173
|
+
]);
|
|
174
|
+
|
|
175
|
+
const SseContentBlockDeltaEvent = z.object({
|
|
176
|
+
type: z.literal("content_block_delta"),
|
|
177
|
+
index: z.number(),
|
|
178
|
+
delta: SseDeltaBlock,
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
const SseContentBlockStopEvent = z.object({
|
|
182
|
+
type: z.literal("content_block_stop"),
|
|
183
|
+
index: z.number(),
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
const SseMessageDeltaEvent = z.object({
|
|
187
|
+
type: z.literal("message_delta"),
|
|
188
|
+
delta: z.object({
|
|
189
|
+
stop_reason: z.string().nullable(),
|
|
190
|
+
stop_sequence: z.string().nullable().optional(),
|
|
191
|
+
}),
|
|
192
|
+
usage: z
|
|
193
|
+
.object({
|
|
194
|
+
output_tokens: z.number(),
|
|
195
|
+
input_tokens: z.number().optional(),
|
|
196
|
+
cache_creation_input_tokens: z.number().optional(),
|
|
197
|
+
cache_read_input_tokens: z.number().optional(),
|
|
198
|
+
})
|
|
199
|
+
.passthrough(),
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
const SseMessageStopEvent = z.object({
|
|
203
|
+
type: z.literal("message_stop"),
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
const SsePingEvent = z.object({
|
|
207
|
+
type: z.literal("ping"),
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
const SseErrorEvent = z.object({
|
|
211
|
+
type: z.literal("error"),
|
|
212
|
+
error: z.object({
|
|
213
|
+
type: z.string(),
|
|
214
|
+
message: z.string(),
|
|
215
|
+
}),
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
export const SseEventSchema = z.discriminatedUnion("type", [
|
|
219
|
+
SseMessageStartEvent,
|
|
220
|
+
SseContentBlockStartEvent,
|
|
221
|
+
SseContentBlockDeltaEvent,
|
|
222
|
+
SseContentBlockStopEvent,
|
|
223
|
+
SseMessageDeltaEvent,
|
|
224
|
+
SseMessageStopEvent,
|
|
225
|
+
SsePingEvent,
|
|
226
|
+
SseErrorEvent,
|
|
227
|
+
]);
|
|
228
|
+
|
|
229
|
+
export type AnthropicRequest = z.infer<typeof AnthropicRequestSchema>;
|
|
230
|
+
export type AnthropicResponse = z.infer<typeof AnthropicResponseSchema>;
|
|
231
|
+
export type ResponseContentBlockType = z.infer<typeof ResponseContentBlock>;
|
|
232
|
+
|
|
233
|
+
// Backward-compatible aliases (originally named Inspector*)
|
|
234
|
+
export const InspectorRequestSchema = AnthropicRequestSchema;
|
|
235
|
+
export const InspectorResponseSchema = AnthropicResponseSchema;
|
|
236
|
+
export type InspectorRequest = AnthropicRequest;
|
|
237
|
+
export type InspectorResponse = AnthropicResponse;
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import type { CapturedLog, JsonValue } from "../../schemas";
|
|
2
|
+
import { trustAsJsonValue } from "../jsonSchema";
|
|
3
|
+
import { SseEventSchema } from "./schemas";
|
|
4
|
+
|
|
5
|
+
type StreamTextBlock = { type: "text"; text: string };
|
|
6
|
+
type StreamThinkingBlock = { type: "thinking"; thinking: string; signature: string };
|
|
7
|
+
type StreamThinkBlock = { type: "think"; thinking: string; signature: string };
|
|
8
|
+
type StreamToolUseBlock = { type: "tool_use"; id: string; name: string; inputJson: string };
|
|
9
|
+
type StreamBlock = StreamTextBlock | StreamThinkingBlock | StreamThinkBlock | StreamToolUseBlock;
|
|
10
|
+
|
|
11
|
+
function parseInputJson(json: string): Record<string, unknown> {
|
|
12
|
+
if (json === "") return {};
|
|
13
|
+
try {
|
|
14
|
+
const parsed: unknown = JSON.parse(json);
|
|
15
|
+
if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
16
|
+
return { ...parsed };
|
|
17
|
+
}
|
|
18
|
+
return {};
|
|
19
|
+
} catch {
|
|
20
|
+
return {};
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function finalizeBlock(block: StreamBlock): Record<string, unknown> {
|
|
25
|
+
switch (block.type) {
|
|
26
|
+
case "text":
|
|
27
|
+
return { type: "text", text: block.text };
|
|
28
|
+
case "thinking": {
|
|
29
|
+
const out: Record<string, unknown> = { type: "thinking", thinking: block.thinking };
|
|
30
|
+
if (block.signature !== "") out.signature = block.signature;
|
|
31
|
+
return out;
|
|
32
|
+
}
|
|
33
|
+
case "think": {
|
|
34
|
+
const out: Record<string, unknown> = { type: "think", thinking: block.thinking };
|
|
35
|
+
if (block.signature !== "") out.signature = block.signature;
|
|
36
|
+
return out;
|
|
37
|
+
}
|
|
38
|
+
case "tool_use":
|
|
39
|
+
return {
|
|
40
|
+
type: "tool_use",
|
|
41
|
+
id: block.id,
|
|
42
|
+
name: block.name,
|
|
43
|
+
input: parseInputJson(block.inputJson),
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Extract Anthropic streaming response and return normalized JSON.
|
|
50
|
+
* Optionally collects SSE chunks into log.streamingChunks for debugging/display.
|
|
51
|
+
*/
|
|
52
|
+
export function extractAnthropicStream(
|
|
53
|
+
raw: string,
|
|
54
|
+
log: CapturedLog,
|
|
55
|
+
fallbackModel?: string,
|
|
56
|
+
collectChunks?: boolean,
|
|
57
|
+
): string {
|
|
58
|
+
const blocks = new Map<number, StreamBlock>();
|
|
59
|
+
let id = "";
|
|
60
|
+
let model = "";
|
|
61
|
+
let stopReason: string | null = null;
|
|
62
|
+
let stopSequence: string | null = null;
|
|
63
|
+
let inputTokens = 0;
|
|
64
|
+
let outputTokens = 0;
|
|
65
|
+
|
|
66
|
+
const MAX_CHUNKS = 1000;
|
|
67
|
+
let chunkIndex = 0;
|
|
68
|
+
let streamStartMs = 0;
|
|
69
|
+
const chunks: Array<{ index: number; timestamp: number; type: string; data: JsonValue }> = [];
|
|
70
|
+
|
|
71
|
+
for (const line of raw.split("\n")) {
|
|
72
|
+
const trimmedLine = line.trim();
|
|
73
|
+
if (!trimmedLine.startsWith("data: ")) continue;
|
|
74
|
+
try {
|
|
75
|
+
const json: unknown = JSON.parse(trimmedLine.slice(6));
|
|
76
|
+
const parsed = SseEventSchema.safeParse(json);
|
|
77
|
+
if (!parsed.success) continue;
|
|
78
|
+
const data = parsed.data;
|
|
79
|
+
|
|
80
|
+
if (chunkIndex === 0) streamStartMs = Date.now();
|
|
81
|
+
|
|
82
|
+
if (collectChunks === true && chunks.length < MAX_CHUNKS) {
|
|
83
|
+
chunks.push({
|
|
84
|
+
index: chunkIndex,
|
|
85
|
+
timestamp: Date.now() - streamStartMs,
|
|
86
|
+
type: data.type,
|
|
87
|
+
// `data` has already been validated by SseEventSchema above; the
|
|
88
|
+
// recursive JsonValue walk is a redundant full-tree zod parse on
|
|
89
|
+
// every SSE event. See trustAsJsonValue for the rationale.
|
|
90
|
+
data: trustAsJsonValue(data),
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
chunkIndex++;
|
|
94
|
+
|
|
95
|
+
switch (data.type) {
|
|
96
|
+
case "message_start":
|
|
97
|
+
id = data.message.id;
|
|
98
|
+
model = data.message.model;
|
|
99
|
+
inputTokens = data.message.usage.input_tokens;
|
|
100
|
+
log.inputTokens = inputTokens;
|
|
101
|
+
log.cacheCreationInputTokens = data.message.usage.cache_creation_input_tokens ?? null;
|
|
102
|
+
log.cacheReadInputTokens = data.message.usage.cache_read_input_tokens ?? null;
|
|
103
|
+
if (log.model === null) log.model = model;
|
|
104
|
+
break;
|
|
105
|
+
case "content_block_start": {
|
|
106
|
+
const cb = data.content_block;
|
|
107
|
+
switch (cb.type) {
|
|
108
|
+
case "text":
|
|
109
|
+
blocks.set(data.index, { type: "text", text: cb.text ?? "" });
|
|
110
|
+
break;
|
|
111
|
+
case "thinking":
|
|
112
|
+
blocks.set(data.index, {
|
|
113
|
+
type: "thinking",
|
|
114
|
+
thinking: cb.thinking ?? "",
|
|
115
|
+
signature: cb.signature ?? "",
|
|
116
|
+
});
|
|
117
|
+
break;
|
|
118
|
+
case "think":
|
|
119
|
+
blocks.set(data.index, {
|
|
120
|
+
type: "think",
|
|
121
|
+
thinking: cb.thinking ?? "",
|
|
122
|
+
signature: cb.signature ?? "",
|
|
123
|
+
});
|
|
124
|
+
break;
|
|
125
|
+
case "tool_use":
|
|
126
|
+
blocks.set(data.index, {
|
|
127
|
+
type: "tool_use",
|
|
128
|
+
id: cb.id,
|
|
129
|
+
name: cb.name,
|
|
130
|
+
inputJson: "",
|
|
131
|
+
});
|
|
132
|
+
break;
|
|
133
|
+
}
|
|
134
|
+
break;
|
|
135
|
+
}
|
|
136
|
+
case "content_block_delta": {
|
|
137
|
+
const block = blocks.get(data.index);
|
|
138
|
+
if (block === undefined) break;
|
|
139
|
+
const delta = data.delta;
|
|
140
|
+
if (delta.type === "text_delta" && block.type === "text") {
|
|
141
|
+
block.text += delta.text;
|
|
142
|
+
} else if (
|
|
143
|
+
delta.type === "thinking_delta" &&
|
|
144
|
+
(block.type === "thinking" || block.type === "think")
|
|
145
|
+
) {
|
|
146
|
+
block.thinking += delta.thinking;
|
|
147
|
+
} else if (
|
|
148
|
+
delta.type === "signature_delta" &&
|
|
149
|
+
(block.type === "thinking" || block.type === "think")
|
|
150
|
+
) {
|
|
151
|
+
block.signature += delta.signature;
|
|
152
|
+
} else if (delta.type === "input_json_delta" && block.type === "tool_use") {
|
|
153
|
+
block.inputJson += delta.partial_json;
|
|
154
|
+
}
|
|
155
|
+
break;
|
|
156
|
+
}
|
|
157
|
+
case "message_delta":
|
|
158
|
+
stopReason = data.delta.stop_reason;
|
|
159
|
+
stopSequence = data.delta.stop_sequence ?? null;
|
|
160
|
+
outputTokens = data.usage.output_tokens;
|
|
161
|
+
log.outputTokens = outputTokens;
|
|
162
|
+
// Cache tokens may also be present in message_delta usage
|
|
163
|
+
if (data.usage.cache_creation_input_tokens !== undefined) {
|
|
164
|
+
log.cacheCreationInputTokens = data.usage.cache_creation_input_tokens;
|
|
165
|
+
}
|
|
166
|
+
if (data.usage.cache_read_input_tokens !== undefined) {
|
|
167
|
+
log.cacheReadInputTokens = data.usage.cache_read_input_tokens;
|
|
168
|
+
}
|
|
169
|
+
break;
|
|
170
|
+
case "error":
|
|
171
|
+
// Store error info on the log for display
|
|
172
|
+
log.error = data.error.message;
|
|
173
|
+
break;
|
|
174
|
+
case "content_block_stop":
|
|
175
|
+
case "message_stop":
|
|
176
|
+
case "ping":
|
|
177
|
+
break;
|
|
178
|
+
}
|
|
179
|
+
} catch {
|
|
180
|
+
// non-JSON SSE line, skip
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if (collectChunks === true) {
|
|
185
|
+
log.streamingChunks = {
|
|
186
|
+
chunks,
|
|
187
|
+
truncated: chunkIndex > MAX_CHUNKS,
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const orderedContent = [...blocks.entries()]
|
|
192
|
+
.sort(([a], [b]) => a - b)
|
|
193
|
+
.map(([, block]) => finalizeBlock(block));
|
|
194
|
+
|
|
195
|
+
return JSON.stringify({
|
|
196
|
+
id,
|
|
197
|
+
type: "message",
|
|
198
|
+
model: model !== "" ? model : (fallbackModel ?? ""),
|
|
199
|
+
role: "assistant",
|
|
200
|
+
content: orderedContent,
|
|
201
|
+
stop_reason: stopReason,
|
|
202
|
+
stop_sequence: stopSequence,
|
|
203
|
+
usage: { input_tokens: inputTokens, output_tokens: outputTokens },
|
|
204
|
+
});
|
|
205
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { CapturedLog, RequestFormat, TokenUsage } from "../schemas";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Structured result of parsing a raw request body.
|
|
5
|
+
*/
|
|
6
|
+
export type ParsedRequest = {
|
|
7
|
+
model: string | null;
|
|
8
|
+
sessionId: string | null;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* FormatHandler defines the contract for all API format implementations.
|
|
13
|
+
*
|
|
14
|
+
* Each API format (Anthropic, OpenAI) provides its own handler that encapsulates
|
|
15
|
+
* request parsing, response parsing, SSE stream extraction, and token extraction.
|
|
16
|
+
* This replaces the scattered if/else format branching previously in handler.ts.
|
|
17
|
+
*/
|
|
18
|
+
export type FormatHandler = {
|
|
19
|
+
/** The format identifier */
|
|
20
|
+
readonly format: RequestFormat;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Parse a raw request body to extract model name and metadata.
|
|
24
|
+
*/
|
|
25
|
+
parseRequest(rawBody: string, headers?: Headers): ParsedRequest | null;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Extract token usage from a non-streaming response body.
|
|
29
|
+
*/
|
|
30
|
+
extractTokens(responseBody: string): TokenUsage;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Extract structured content from a streaming SSE response.
|
|
34
|
+
*/
|
|
35
|
+
extractStream(
|
|
36
|
+
raw: string,
|
|
37
|
+
log: CapturedLog,
|
|
38
|
+
fallbackModel?: string,
|
|
39
|
+
collectChunks?: boolean,
|
|
40
|
+
): string;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Detect if a raw request body uses this format.
|
|
44
|
+
*/
|
|
45
|
+
detectFormat(rawBody: string | null): boolean;
|
|
46
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// Import submodules to trigger handler registration
|
|
2
|
+
import "./anthropic/index";
|
|
3
|
+
import "./openai/index";
|
|
4
|
+
|
|
5
|
+
// Import providers to trigger self-registration
|
|
6
|
+
import "./anthropic/anthropicProvider";
|
|
7
|
+
import "./openai/provider";
|
|
8
|
+
import "./openai/alibabaProvider";
|
|
9
|
+
|
|
10
|
+
export type { FormatHandler, ParsedRequest } from "./handler";
|
|
11
|
+
export { formatRegistry, formatForPath, requestFormatForPath } from "./registry";
|
|
12
|
+
export { registry } from "./providers";
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Shared JSON value type for streaming chunks.
|
|
5
|
+
* Defined in a separate file to avoid circular dependencies.
|
|
6
|
+
*/
|
|
7
|
+
export type JsonValue =
|
|
8
|
+
| string
|
|
9
|
+
| number
|
|
10
|
+
| boolean
|
|
11
|
+
| null
|
|
12
|
+
| JsonValue[]
|
|
13
|
+
| { [key: string]: JsonValue };
|
|
14
|
+
|
|
15
|
+
export const JsonValueSchema: z.ZodType<JsonValue> = z.lazy(() =>
|
|
16
|
+
z.union([
|
|
17
|
+
z.string(),
|
|
18
|
+
z.number(),
|
|
19
|
+
z.boolean(),
|
|
20
|
+
z.null(),
|
|
21
|
+
z.array(JsonValueSchema),
|
|
22
|
+
z.record(z.string(), JsonValueSchema),
|
|
23
|
+
]),
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Re-types a value as `JsonValue` without re-walking it. Use this ONLY when
|
|
28
|
+
* the value has already been validated (e.g., via `SseEventSchema.safeParse`)
|
|
29
|
+
* AND originated from `JSON.parse`. Skipping the recursive `JsonValueSchema`
|
|
30
|
+
* walk avoids a second full-tree zod parse on every event of every streaming
|
|
31
|
+
* response. Centralized here so the eslint-disable is one site, not two.
|
|
32
|
+
*/
|
|
33
|
+
export function trustAsJsonValue<T>(value: T): JsonValue {
|
|
34
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
35
|
+
return value as unknown as JsonValue;
|
|
36
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { CapturedLog } from "../../schemas";
|
|
2
|
+
import type { ProviderProtocol } from "../protocol";
|
|
3
|
+
import { registry } from "../providers";
|
|
4
|
+
import { extractOpenAIStream } from "./stream";
|
|
5
|
+
|
|
6
|
+
const DEFAULT_ALIBABA_UPSTREAM = "https://dashscope.aliyuncs.com/compatible-mode/v1";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Alibaba Provider Implementation (DashScope)
|
|
10
|
+
*/
|
|
11
|
+
export const alibabaProvider: ProviderProtocol = {
|
|
12
|
+
name: "alibaba",
|
|
13
|
+
|
|
14
|
+
matches(model: string): boolean {
|
|
15
|
+
// Normalize: lowercase, replace whitespace with hyphens
|
|
16
|
+
const m = model.toLowerCase().replace(/\s+/g, "-");
|
|
17
|
+
// Match glm-5* and glm-5.1* models
|
|
18
|
+
if (m.startsWith("glm-5")) {
|
|
19
|
+
return true;
|
|
20
|
+
}
|
|
21
|
+
// Match qwen models (qwen3.6-plus, qwen3.7-max, Qwen3.6 Plus, etc.)
|
|
22
|
+
if (m.startsWith("qwen")) {
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
return false;
|
|
26
|
+
},
|
|
27
|
+
|
|
28
|
+
getUpstreamBase(_isChatCompletions: boolean, _providerConfig?: { baseUrl?: string }): string {
|
|
29
|
+
return DEFAULT_ALIBABA_UPSTREAM;
|
|
30
|
+
},
|
|
31
|
+
|
|
32
|
+
extractStream(raw: string, log: CapturedLog, fallbackModel?: string): string {
|
|
33
|
+
return extractOpenAIStream(raw, log, fallbackModel);
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
// Register the provider
|
|
38
|
+
registry.register(alibabaProvider);
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import type { FormatHandler, ParsedRequest } from "../handler";
|
|
2
|
+
import type { CapturedLog, TokenUsage } from "../../schemas";
|
|
3
|
+
import { OpenAIRequestSchema, OpenAIResponseSchema, parseOpenAIResponse } from "./schemas";
|
|
4
|
+
import { extractOpenAIStream } from "./stream";
|
|
5
|
+
|
|
6
|
+
export const OpenAIFormatHandler: FormatHandler = {
|
|
7
|
+
format: "openai",
|
|
8
|
+
|
|
9
|
+
parseRequest(rawBody: string, headers?: Headers): ParsedRequest | null {
|
|
10
|
+
try {
|
|
11
|
+
const json: unknown = JSON.parse(rawBody);
|
|
12
|
+
const result = OpenAIRequestSchema.safeParse(json);
|
|
13
|
+
if (result.success) {
|
|
14
|
+
return {
|
|
15
|
+
model: result.data.model,
|
|
16
|
+
sessionId: headers?.get("x-session-affinity") ?? null,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
return null;
|
|
20
|
+
} catch {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
|
|
25
|
+
extractTokens(responseBody: string): TokenUsage {
|
|
26
|
+
const parsed = parseOpenAIResponse(responseBody);
|
|
27
|
+
if (parsed) {
|
|
28
|
+
// OpenAI puts cached_tokens in usage.prompt_tokens_details (passthrough field)
|
|
29
|
+
let cacheReadInputTokens: number | null = null;
|
|
30
|
+
try {
|
|
31
|
+
const raw: unknown = JSON.parse(responseBody);
|
|
32
|
+
if (raw !== null && typeof raw === "object" && !Array.isArray(raw)) {
|
|
33
|
+
const usageDesc = Object.getOwnPropertyDescriptor(raw, "usage");
|
|
34
|
+
if (
|
|
35
|
+
usageDesc !== undefined &&
|
|
36
|
+
typeof usageDesc.value === "object" &&
|
|
37
|
+
usageDesc.value !== null
|
|
38
|
+
) {
|
|
39
|
+
const detailsDesc = Object.getOwnPropertyDescriptor(
|
|
40
|
+
usageDesc.value,
|
|
41
|
+
"prompt_tokens_details",
|
|
42
|
+
);
|
|
43
|
+
if (
|
|
44
|
+
detailsDesc !== undefined &&
|
|
45
|
+
typeof detailsDesc.value === "object" &&
|
|
46
|
+
detailsDesc.value !== null
|
|
47
|
+
) {
|
|
48
|
+
const cacheDesc = Object.getOwnPropertyDescriptor(detailsDesc.value, "cached_tokens");
|
|
49
|
+
if (cacheDesc !== undefined && typeof cacheDesc.value === "number") {
|
|
50
|
+
cacheReadInputTokens = cacheDesc.value;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
} catch {
|
|
56
|
+
// ignore parse errors
|
|
57
|
+
}
|
|
58
|
+
return {
|
|
59
|
+
inputTokens: parsed.usage.prompt_tokens ?? null,
|
|
60
|
+
outputTokens: parsed.usage.completion_tokens ?? null,
|
|
61
|
+
cacheCreationInputTokens: null,
|
|
62
|
+
cacheReadInputTokens,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
return {
|
|
66
|
+
inputTokens: null,
|
|
67
|
+
outputTokens: null,
|
|
68
|
+
cacheCreationInputTokens: null,
|
|
69
|
+
cacheReadInputTokens: null,
|
|
70
|
+
};
|
|
71
|
+
},
|
|
72
|
+
|
|
73
|
+
extractStream(
|
|
74
|
+
raw: string,
|
|
75
|
+
log: CapturedLog,
|
|
76
|
+
fallbackModel?: string,
|
|
77
|
+
collectChunks?: boolean,
|
|
78
|
+
): string {
|
|
79
|
+
return extractOpenAIStream(raw, log, fallbackModel, collectChunks);
|
|
80
|
+
},
|
|
81
|
+
|
|
82
|
+
detectFormat(rawBody: string | null): boolean {
|
|
83
|
+
if (rawBody === null) return false;
|
|
84
|
+
try {
|
|
85
|
+
const json: unknown = JSON.parse(rawBody);
|
|
86
|
+
if (typeof json === "object" && json !== null && !Array.isArray(json)) {
|
|
87
|
+
const keys = Object.keys(json);
|
|
88
|
+
// OpenAI has `model` and `messages` at the top level, but NOT `system`
|
|
89
|
+
return keys.includes("model") && keys.includes("messages") && !keys.includes("system");
|
|
90
|
+
}
|
|
91
|
+
return false;
|
|
92
|
+
} catch {
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// Register format handler
|
|
2
|
+
import "./register";
|
|
3
|
+
|
|
4
|
+
// Schemas
|
|
5
|
+
export {
|
|
6
|
+
OpenAIRequestSchema,
|
|
7
|
+
OpenAIResponseSchema,
|
|
8
|
+
OpenAISSERawChunkSchema,
|
|
9
|
+
OpenAIMessage,
|
|
10
|
+
OpenAIMessageContent,
|
|
11
|
+
OpenAIToolDefinition,
|
|
12
|
+
OpenAIChoice,
|
|
13
|
+
OpenAIChoiceDelta,
|
|
14
|
+
parseOpenAIResponse,
|
|
15
|
+
} from "./schemas";
|
|
16
|
+
|
|
17
|
+
// Handler
|
|
18
|
+
export { OpenAIFormatHandler } from "./handler";
|
|
19
|
+
|
|
20
|
+
// Stream extraction
|
|
21
|
+
export { extractOpenAIStream } from "./stream";
|
|
22
|
+
|
|
23
|
+
// Providers
|
|
24
|
+
export { openaiProvider } from "./provider";
|
|
25
|
+
export { alibabaProvider } from "./alibabaProvider";
|