@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,30 @@
|
|
|
1
|
+
import useSWR, { type SWRResponse } from "swr";
|
|
2
|
+
import { fetchJson } from "./apiClient";
|
|
3
|
+
import { ProviderConfigSchema, type ProviderConfig } from "./providerContract";
|
|
4
|
+
|
|
5
|
+
async function fetcher(url: string): Promise<ProviderConfig[]> {
|
|
6
|
+
return fetchJson(
|
|
7
|
+
url,
|
|
8
|
+
ProviderConfigSchema.array(),
|
|
9
|
+
undefined,
|
|
10
|
+
(response) => `Failed to fetch ${url}: ${response.status}`,
|
|
11
|
+
);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function useProviders() {
|
|
15
|
+
const response: SWRResponse<ProviderConfig[], Error> = useSWR<ProviderConfig[], Error>(
|
|
16
|
+
"/api/providers",
|
|
17
|
+
fetcher,
|
|
18
|
+
{
|
|
19
|
+
revalidateOnFocus: false,
|
|
20
|
+
revalidateIfStale: false,
|
|
21
|
+
},
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
return {
|
|
25
|
+
providers: response.data ?? [],
|
|
26
|
+
isLoading: response.isLoading,
|
|
27
|
+
isError: response.error,
|
|
28
|
+
mutate: response.mutate,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import useSWR, { type SWRResponse, useSWRConfig } from "swr";
|
|
2
|
+
import { fetchJson } from "./apiClient";
|
|
3
|
+
import {
|
|
4
|
+
DEFAULT_SLOW_RESPONSE_THRESHOLD_SECONDS,
|
|
5
|
+
RuntimeConfigSchema,
|
|
6
|
+
type RuntimeConfig,
|
|
7
|
+
} from "./runtimeConfig";
|
|
8
|
+
|
|
9
|
+
export const STRIP_CONFIG_SWR_KEY = "/api/config";
|
|
10
|
+
|
|
11
|
+
async function fetcher(url: string): Promise<RuntimeConfig> {
|
|
12
|
+
return fetchJson(
|
|
13
|
+
url,
|
|
14
|
+
RuntimeConfigSchema,
|
|
15
|
+
undefined,
|
|
16
|
+
(response) => `Failed to fetch ${url}: ${response.status}`,
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* PATCH the runtime config. Exported separately for testability.
|
|
22
|
+
*/
|
|
23
|
+
export async function setRuntimeConfig(patch: Partial<RuntimeConfig>): Promise<RuntimeConfig> {
|
|
24
|
+
return fetchJson(
|
|
25
|
+
STRIP_CONFIG_SWR_KEY,
|
|
26
|
+
RuntimeConfigSchema,
|
|
27
|
+
{
|
|
28
|
+
method: "PATCH",
|
|
29
|
+
headers: { "content-type": "application/json" },
|
|
30
|
+
body: JSON.stringify(patch),
|
|
31
|
+
},
|
|
32
|
+
(response) => `PATCH failed with status ${response.status}`,
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export type UseStripConfig = {
|
|
37
|
+
strip: boolean;
|
|
38
|
+
slowResponseThresholdSeconds: number;
|
|
39
|
+
isLoading: boolean;
|
|
40
|
+
isError: boolean;
|
|
41
|
+
setStrip: (next: boolean) => Promise<void>;
|
|
42
|
+
setSlowResponseThresholdSeconds: (next: number) => Promise<void>;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Hook reading the runtime config from /api/config.
|
|
47
|
+
*
|
|
48
|
+
* - `strip` is the live value from the server (or the optimistic value mid-PATCH).
|
|
49
|
+
* - `slowResponseThresholdSeconds` controls the UI's slow-response indicator.
|
|
50
|
+
* - `setStrip(next)` PATCHes the server with optimistic update; on failure
|
|
51
|
+
* it throws and SWR rolls back the optimistic value.
|
|
52
|
+
*/
|
|
53
|
+
export function useStripConfig(): UseStripConfig {
|
|
54
|
+
const response: SWRResponse<RuntimeConfig, Error> = useSWR<RuntimeConfig, Error>(
|
|
55
|
+
STRIP_CONFIG_SWR_KEY,
|
|
56
|
+
fetcher,
|
|
57
|
+
{
|
|
58
|
+
revalidateOnFocus: false,
|
|
59
|
+
revalidateIfStale: false,
|
|
60
|
+
},
|
|
61
|
+
);
|
|
62
|
+
const { mutate: globalMutate } = useSWRConfig();
|
|
63
|
+
|
|
64
|
+
const strip = response.data?.stripClaudeCodeBillingHeader ?? false;
|
|
65
|
+
const slowResponseThresholdSeconds =
|
|
66
|
+
response.data?.slowResponseThresholdSeconds ?? DEFAULT_SLOW_RESPONSE_THRESHOLD_SECONDS;
|
|
67
|
+
|
|
68
|
+
const optimisticConfig = (patch: Partial<RuntimeConfig>): RuntimeConfig => ({
|
|
69
|
+
stripClaudeCodeBillingHeader: response.data?.stripClaudeCodeBillingHeader ?? false,
|
|
70
|
+
hasSeenOnboarding: response.data?.hasSeenOnboarding ?? false,
|
|
71
|
+
slowResponseThresholdSeconds:
|
|
72
|
+
response.data?.slowResponseThresholdSeconds ?? DEFAULT_SLOW_RESPONSE_THRESHOLD_SECONDS,
|
|
73
|
+
...patch,
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
const setStrip = async (next: boolean): Promise<void> => {
|
|
77
|
+
await globalMutate(
|
|
78
|
+
STRIP_CONFIG_SWR_KEY,
|
|
79
|
+
setRuntimeConfig({ stripClaudeCodeBillingHeader: next }),
|
|
80
|
+
{
|
|
81
|
+
optimisticData: optimisticConfig({ stripClaudeCodeBillingHeader: next }),
|
|
82
|
+
rollbackOnError: true,
|
|
83
|
+
revalidate: false,
|
|
84
|
+
},
|
|
85
|
+
);
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
const setSlowResponseThresholdSeconds = async (next: number): Promise<void> => {
|
|
89
|
+
await globalMutate(
|
|
90
|
+
STRIP_CONFIG_SWR_KEY,
|
|
91
|
+
setRuntimeConfig({ slowResponseThresholdSeconds: next }),
|
|
92
|
+
{
|
|
93
|
+
optimisticData: optimisticConfig({ slowResponseThresholdSeconds: next }),
|
|
94
|
+
rollbackOnError: true,
|
|
95
|
+
revalidate: false,
|
|
96
|
+
},
|
|
97
|
+
);
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
return {
|
|
101
|
+
strip,
|
|
102
|
+
slowResponseThresholdSeconds,
|
|
103
|
+
isLoading: response.isLoading,
|
|
104
|
+
isError: response.error !== undefined,
|
|
105
|
+
setStrip,
|
|
106
|
+
setSlowResponseThresholdSeconds,
|
|
107
|
+
};
|
|
108
|
+
}
|
package/src/lib/utils.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type ClassValue, clsx } from "clsx";
|
|
2
|
+
import { twMerge } from "tailwind-merge";
|
|
3
|
+
|
|
4
|
+
export function cn(...inputs: ClassValue[]): string {
|
|
5
|
+
return twMerge(clsx(inputs));
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function formatTokens(count: number): string {
|
|
9
|
+
if (count >= 1_000_000) return (count / 1_000_000).toFixed(1).replace(/\.0$/, "") + "M";
|
|
10
|
+
return (count / 1000).toFixed(1).replace(/\.0$/, "") + "K";
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export type StatusCategory = "success" | "client_error" | "server_error" | "pending";
|
|
14
|
+
|
|
15
|
+
export function getStatusCategory(status: number | null): StatusCategory {
|
|
16
|
+
if (status === null) return "pending";
|
|
17
|
+
if (status >= 200 && status < 300) return "success";
|
|
18
|
+
if (status >= 400 && status < 500) return "client_error";
|
|
19
|
+
if (status >= 500) return "server_error";
|
|
20
|
+
return "pending";
|
|
21
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/* eslint-disable functional/no-throw-statements */
|
|
2
|
+
/**
|
|
3
|
+
* HTTP loopback helper for MCP tool handlers.
|
|
4
|
+
*
|
|
5
|
+
* Why HTTP loopback (not direct function calls): see
|
|
6
|
+
* `openspec/changes/add-mcp-server/design.md` decision D2. All MCP tools
|
|
7
|
+
* delegate to existing `/api/*` endpoints so any future cross-cutting
|
|
8
|
+
* middleware (auth, rate-limit, audit, metrics) added to `/api` is
|
|
9
|
+
* automatically inherited by MCP without duplicate plumbing.
|
|
10
|
+
*
|
|
11
|
+
* NOTE: TanStack Start / Nitro may expose an in-process route invocation
|
|
12
|
+
* API (e.g. Nitro's `$fetch` helper) that would let us skip the real HTTP
|
|
13
|
+
* round-trip while preserving the routing contract. As of this writing
|
|
14
|
+
* that investigation is open (tasks.md 2.3). If/when adopted, the public
|
|
15
|
+
* surface of this module — `callApi(path, init?)` returning a `Response`
|
|
16
|
+
* — should stay identical so callers don't change.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import { getCurrentPort } from "../lib/serverPort";
|
|
20
|
+
|
|
21
|
+
const DEFAULT_TIMEOUT_MS = 30_000;
|
|
22
|
+
|
|
23
|
+
export type CallApiOptions = RequestInit & {
|
|
24
|
+
/** Override default 30s timeout. */
|
|
25
|
+
timeoutMs?: number;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export class LoopbackTimeoutError extends Error {
|
|
29
|
+
constructor(
|
|
30
|
+
public readonly path: string,
|
|
31
|
+
public readonly timeoutMs: number,
|
|
32
|
+
) {
|
|
33
|
+
super(`Loopback call to ${path} timed out after ${timeoutMs}ms`);
|
|
34
|
+
this.name = "LoopbackTimeoutError";
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Make an HTTP request to one of the inspector's own /api/* endpoints
|
|
40
|
+
* via 127.0.0.1 loopback. The returned Response is a standard Web
|
|
41
|
+
* Response; callers decide whether to call .json(), .text(), .arrayBuffer().
|
|
42
|
+
*
|
|
43
|
+
* `path` MUST start with `/` (e.g. `/api/logs`).
|
|
44
|
+
*/
|
|
45
|
+
export async function callApi(path: string, options: CallApiOptions = {}): Promise<Response> {
|
|
46
|
+
if (!path.startsWith("/")) {
|
|
47
|
+
throw new Error(`callApi: path must start with '/', got: ${path}`);
|
|
48
|
+
}
|
|
49
|
+
const port = getCurrentPort();
|
|
50
|
+
const url = `http://127.0.0.1:${port}${path}`;
|
|
51
|
+
|
|
52
|
+
const { timeoutMs = DEFAULT_TIMEOUT_MS, signal: userSignal, ...rest } = options;
|
|
53
|
+
|
|
54
|
+
const controller = new AbortController();
|
|
55
|
+
const timeoutHandle = setTimeout(() => controller.abort(), timeoutMs);
|
|
56
|
+
|
|
57
|
+
// If caller passed their own signal, chain it.
|
|
58
|
+
if (userSignal !== undefined && userSignal !== null) {
|
|
59
|
+
if (userSignal.aborted) {
|
|
60
|
+
controller.abort();
|
|
61
|
+
} else {
|
|
62
|
+
userSignal.addEventListener("abort", () => controller.abort(), { once: true });
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
try {
|
|
67
|
+
return await fetch(url, { ...rest, signal: controller.signal });
|
|
68
|
+
} catch (err) {
|
|
69
|
+
if (err instanceof Error && err.name === "AbortError") {
|
|
70
|
+
throw new LoopbackTimeoutError(path, timeoutMs);
|
|
71
|
+
}
|
|
72
|
+
throw err;
|
|
73
|
+
} finally {
|
|
74
|
+
clearTimeout(timeoutHandle);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Format-parser-driven preview extractor for the MCP `inspector_list_logs`
|
|
3
|
+
* "thick summary" shape. See `openspec/changes/add-mcp-server/design.md`
|
|
4
|
+
* decision D5.
|
|
5
|
+
*
|
|
6
|
+
* Why we re-parse with the format schemas (not slice `rawRequestBody`):
|
|
7
|
+
* a 500-char prefix is almost always JSON envelope + system prompt boilerplate
|
|
8
|
+
* with zero signal about what the user actually asked. The format parsers
|
|
9
|
+
* give us the first text block of the last user message, which is what an
|
|
10
|
+
* agent needs to make a "is this the log I care about?" judgment from
|
|
11
|
+
* `list_logs` alone.
|
|
12
|
+
*
|
|
13
|
+
* Null returns are an expected and frequent outcome — they cover:
|
|
14
|
+
* - `apiFormat === "unknown"`
|
|
15
|
+
* - `rawRequestBody` / `responseText` is null
|
|
16
|
+
* - JSON.parse failure
|
|
17
|
+
* - schema validation failure
|
|
18
|
+
* - no qualifying user / assistant message
|
|
19
|
+
* - the relevant content is non-text (e.g., image-only multimodal block)
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import type { CapturedLog } from "../proxy/schemas";
|
|
23
|
+
import {
|
|
24
|
+
AnthropicRequestSchema,
|
|
25
|
+
AnthropicResponseSchema,
|
|
26
|
+
} from "../proxy/formats/anthropic/schemas";
|
|
27
|
+
import { OpenAIRequestSchema, OpenAIResponseSchema } from "../proxy/formats/openai/schemas";
|
|
28
|
+
|
|
29
|
+
/** Preview length cap, per design D5. */
|
|
30
|
+
const PREVIEW_MAX_CHARS = 500;
|
|
31
|
+
|
|
32
|
+
function truncate(text: string): string {
|
|
33
|
+
return text.length <= PREVIEW_MAX_CHARS ? text : text.slice(0, PREVIEW_MAX_CHARS);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Safely extract the first text from an Anthropic `Message.content` (string
|
|
38
|
+
* or array of blocks). Returns `null` for non-text-only or empty content.
|
|
39
|
+
*/
|
|
40
|
+
function firstAnthropicText(
|
|
41
|
+
content: string | ReadonlyArray<{ type: string; text?: string }>,
|
|
42
|
+
): string | null {
|
|
43
|
+
if (typeof content === "string") {
|
|
44
|
+
return content.length > 0 ? content : null;
|
|
45
|
+
}
|
|
46
|
+
for (const block of content) {
|
|
47
|
+
if (block.type === "text" && typeof block.text === "string" && block.text.length > 0) {
|
|
48
|
+
return block.text;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Safely extract the first text from an OpenAI message content (string or
|
|
56
|
+
* array of `{type:"text"|"image_url",...}`). Returns `null` for non-text /
|
|
57
|
+
* empty content.
|
|
58
|
+
*/
|
|
59
|
+
function firstOpenAIText(
|
|
60
|
+
content: string | ReadonlyArray<{ type: string; text?: string }> | null | undefined,
|
|
61
|
+
): string | null {
|
|
62
|
+
if (content === null || content === undefined) return null;
|
|
63
|
+
if (typeof content === "string") {
|
|
64
|
+
return content.length > 0 ? content : null;
|
|
65
|
+
}
|
|
66
|
+
for (const part of content) {
|
|
67
|
+
if (part.type === "text" && typeof part.text === "string" && part.text.length > 0) {
|
|
68
|
+
return part.text;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Extract a 500-char preview of the last `role: "user"` message's first text
|
|
76
|
+
* block. Returns `null` for unknown format, parse failures, or non-text
|
|
77
|
+
* content. See module-level docstring for the full null-case list.
|
|
78
|
+
*/
|
|
79
|
+
export function extractLastUserMessagePreview(log: CapturedLog): string | null {
|
|
80
|
+
if (log.apiFormat === "unknown") return null;
|
|
81
|
+
if (log.rawRequestBody === null) return null;
|
|
82
|
+
|
|
83
|
+
let json: unknown;
|
|
84
|
+
try {
|
|
85
|
+
json = JSON.parse(log.rawRequestBody);
|
|
86
|
+
} catch {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (log.apiFormat === "anthropic") {
|
|
91
|
+
const parsed = AnthropicRequestSchema.safeParse(json);
|
|
92
|
+
if (!parsed.success) return null;
|
|
93
|
+
// Iterate from the end to find the most recent user turn.
|
|
94
|
+
for (let i = parsed.data.messages.length - 1; i >= 0; i--) {
|
|
95
|
+
const msg = parsed.data.messages[i];
|
|
96
|
+
if (msg && msg.role === "user") {
|
|
97
|
+
const text = firstAnthropicText(msg.content);
|
|
98
|
+
return text === null ? null : truncate(text);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (log.apiFormat === "openai") {
|
|
105
|
+
const parsed = OpenAIRequestSchema.safeParse(json);
|
|
106
|
+
if (!parsed.success) return null;
|
|
107
|
+
for (let i = parsed.data.messages.length - 1; i >= 0; i--) {
|
|
108
|
+
const msg = parsed.data.messages[i];
|
|
109
|
+
if (msg && msg.role === "user") {
|
|
110
|
+
const text = firstOpenAIText(msg.content);
|
|
111
|
+
return text === null ? null : truncate(text);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Extract a 500-char preview of the assistant's response text. Returns
|
|
122
|
+
* `null` for unknown format, parse failures, missing response, or non-text
|
|
123
|
+
* content.
|
|
124
|
+
*/
|
|
125
|
+
export function extractResponsePreview(log: CapturedLog): string | null {
|
|
126
|
+
if (log.apiFormat === "unknown") return null;
|
|
127
|
+
if (log.responseText === null) return null;
|
|
128
|
+
|
|
129
|
+
let json: unknown;
|
|
130
|
+
try {
|
|
131
|
+
json = JSON.parse(log.responseText);
|
|
132
|
+
} catch {
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (log.apiFormat === "anthropic") {
|
|
137
|
+
const parsed = AnthropicResponseSchema.safeParse(json);
|
|
138
|
+
if (!parsed.success) return null;
|
|
139
|
+
for (const block of parsed.data.content) {
|
|
140
|
+
if (block.type === "text" && typeof block.text === "string" && block.text.length > 0) {
|
|
141
|
+
return truncate(block.text);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (log.apiFormat === "openai") {
|
|
148
|
+
const parsed = OpenAIResponseSchema.safeParse(json);
|
|
149
|
+
if (!parsed.success) return null;
|
|
150
|
+
// Pick the first choice that actually carries a text-like content.
|
|
151
|
+
for (const choice of parsed.data.choices) {
|
|
152
|
+
const msg = choice.message;
|
|
153
|
+
if (!msg) continue;
|
|
154
|
+
const direct = firstOpenAIText(msg.content);
|
|
155
|
+
if (direct !== null) return truncate(direct);
|
|
156
|
+
// Some MiniMax / Moonshot-style providers stuff the text into
|
|
157
|
+
// reasoning_content / thinking / think instead of content. We surface
|
|
158
|
+
// whichever is the first non-empty one in a stable priority order.
|
|
159
|
+
const fallback = msg.reasoning_content ?? msg.thinking ?? msg.think;
|
|
160
|
+
if (typeof fallback === "string" && fallback.length > 0) return truncate(fallback);
|
|
161
|
+
}
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return null;
|
|
166
|
+
}
|