@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.
Files changed (400) hide show
  1. package/.output/cli.js +1611 -0
  2. package/.output/nitro.json +17 -0
  3. package/.output/public/assets/CompareDrawer-CU5ZrWcL.js +1 -0
  4. package/.output/public/assets/ProxyViewerContainer-pEBqVp1d.js +101 -0
  5. package/.output/public/assets/ReplayDialog-F58yNg5j.js +1 -0
  6. package/.output/public/assets/RequestAnatomy-C9lT0qE_.js +1 -0
  7. package/.output/public/assets/ResponseView-DHJq6bnz.js +1 -0
  8. package/.output/public/assets/StreamingChunkSequence-BTgfpFUT.js +1 -0
  9. package/.output/public/assets/_sessionId-DsNRbnNm.js +1 -0
  10. package/.output/public/assets/alibaba-TTwafVwX.svg +1 -0
  11. package/.output/public/assets/index-CpWG2hFn.css +1 -0
  12. package/.output/public/assets/index-DmBV8Gve.js +1 -0
  13. package/.output/public/assets/json-viewer-CZVYLR8j.js +14 -0
  14. package/.output/public/assets/main-DHs7FBK3.js +18 -0
  15. package/.output/public/assets/minimax-BPMzvuL-.jpeg +0 -0
  16. package/.output/public/assets/qwen-CONDcHqt.png +0 -0
  17. package/.output/public/assets/zhipuai-BPNAnxo-.svg +219 -0
  18. package/.output/server/_chunks/ssr-renderer.mjs +22 -0
  19. package/.output/server/_libs/@radix-ui/react-accessible-icon+[...].mjs +1 -0
  20. package/.output/server/_libs/@radix-ui/react-dismissable-layer+[...].mjs +210 -0
  21. package/.output/server/_libs/@radix-ui/react-navigation-menu+[...].mjs +2 -0
  22. package/.output/server/_libs/@radix-ui/react-one-time-password-field+[...].mjs +2 -0
  23. package/.output/server/_libs/@radix-ui/react-password-toggle-field+[...].mjs +2 -0
  24. package/.output/server/_libs/@radix-ui/react-use-callback-ref+[...].mjs +11 -0
  25. package/.output/server/_libs/@radix-ui/react-use-controllable-state+[...].mjs +69 -0
  26. package/.output/server/_libs/@radix-ui/react-use-effect-event+[...].mjs +1 -0
  27. package/.output/server/_libs/@radix-ui/react-use-escape-keydown+[...].mjs +17 -0
  28. package/.output/server/_libs/@radix-ui/react-use-is-hydrated+[...].mjs +1 -0
  29. package/.output/server/_libs/@radix-ui/react-use-layout-effect+[...].mjs +6 -0
  30. package/.output/server/_libs/@radix-ui/react-visually-hidden+[...].mjs +34 -0
  31. package/.output/server/_libs/ajv-formats.mjs +330 -0
  32. package/.output/server/_libs/ajv.mjs +11444 -0
  33. package/.output/server/_libs/aria-hidden.mjs +122 -0
  34. package/.output/server/_libs/atomically.mjs +152 -0
  35. package/.output/server/_libs/bail.mjs +8 -0
  36. package/.output/server/_libs/cfworker__json-schema.mjs +1 -0
  37. package/.output/server/_libs/character-entities.mjs +2130 -0
  38. package/.output/server/_libs/class-variance-authority.mjs +44 -0
  39. package/.output/server/_libs/clsx.mjs +16 -0
  40. package/.output/server/_libs/comma-separated-tokens.mjs +10 -0
  41. package/.output/server/_libs/conf.mjs +635 -0
  42. package/.output/server/_libs/cookie-es.mjs +58 -0
  43. package/.output/server/_libs/core-util-is.mjs +75 -0
  44. package/.output/server/_libs/croner.mjs +1 -0
  45. package/.output/server/_libs/crossws.mjs +1 -0
  46. package/.output/server/_libs/debounce-fn.mjs +69 -0
  47. package/.output/server/_libs/decode-named-character-reference+[...].mjs +8 -0
  48. package/.output/server/_libs/dequal.mjs +27 -0
  49. package/.output/server/_libs/detect-node-es.mjs +1 -0
  50. package/.output/server/_libs/devlop.mjs +8 -0
  51. package/.output/server/_libs/diff.mjs +320 -0
  52. package/.output/server/_libs/dot-prop.mjs +265 -0
  53. package/.output/server/_libs/env-paths.mjs +57 -0
  54. package/.output/server/_libs/estree-util-is-identifier-name.mjs +11 -0
  55. package/.output/server/_libs/extend.mjs +97 -0
  56. package/.output/server/_libs/fast-deep-equal.mjs +38 -0
  57. package/.output/server/_libs/fast-uri.mjs +812 -0
  58. package/.output/server/_libs/floating-ui__core.mjs +725 -0
  59. package/.output/server/_libs/floating-ui__dom.mjs +622 -0
  60. package/.output/server/_libs/floating-ui__react-dom.mjs +292 -0
  61. package/.output/server/_libs/floating-ui__utils.mjs +320 -0
  62. package/.output/server/_libs/get-nonce.mjs +9 -0
  63. package/.output/server/_libs/h3-v2.mjs +276 -0
  64. package/.output/server/_libs/h3.mjs +408 -0
  65. package/.output/server/_libs/hast-util-to-jsx-runtime.mjs +388 -0
  66. package/.output/server/_libs/hast-util-whitespace.mjs +10 -0
  67. package/.output/server/_libs/hookable.mjs +1 -0
  68. package/.output/server/_libs/html-url-attributes.mjs +26 -0
  69. package/.output/server/_libs/immediate.mjs +74 -0
  70. package/.output/server/_libs/inherits.mjs +50 -0
  71. package/.output/server/_libs/inline-style-parser.mjs +142 -0
  72. package/.output/server/_libs/is-plain-obj.mjs +10 -0
  73. package/.output/server/_libs/isarray.mjs +14 -0
  74. package/.output/server/_libs/isbot.mjs +20 -0
  75. package/.output/server/_libs/json-schema-traverse.mjs +180 -0
  76. package/.output/server/_libs/jszip.mjs +3051 -0
  77. package/.output/server/_libs/lie.mjs +273 -0
  78. package/.output/server/_libs/lucide-react.mjs +492 -0
  79. package/.output/server/_libs/mdast-util-from-markdown.mjs +717 -0
  80. package/.output/server/_libs/mdast-util-to-hast.mjs +710 -0
  81. package/.output/server/_libs/mdast-util-to-string.mjs +38 -0
  82. package/.output/server/_libs/micromark-core-commonmark.mjs +2259 -0
  83. package/.output/server/_libs/micromark-factory-destination.mjs +94 -0
  84. package/.output/server/_libs/micromark-factory-label.mjs +63 -0
  85. package/.output/server/_libs/micromark-factory-space.mjs +24 -0
  86. package/.output/server/_libs/micromark-factory-title.mjs +65 -0
  87. package/.output/server/_libs/micromark-factory-whitespace.mjs +22 -0
  88. package/.output/server/_libs/micromark-util-character.mjs +44 -0
  89. package/.output/server/_libs/micromark-util-chunked.mjs +36 -0
  90. package/.output/server/_libs/micromark-util-classify-character+[...].mjs +12 -0
  91. package/.output/server/_libs/micromark-util-combine-extensions+[...].mjs +41 -0
  92. package/.output/server/_libs/micromark-util-decode-numeric-character-reference+[...].mjs +19 -0
  93. package/.output/server/_libs/micromark-util-decode-string.mjs +21 -0
  94. package/.output/server/_libs/micromark-util-encode.mjs +1 -0
  95. package/.output/server/_libs/micromark-util-html-tag-name.mjs +69 -0
  96. package/.output/server/_libs/micromark-util-normalize-identifier+[...].mjs +6 -0
  97. package/.output/server/_libs/micromark-util-resolve-all.mjs +15 -0
  98. package/.output/server/_libs/micromark-util-sanitize-uri.mjs +41 -0
  99. package/.output/server/_libs/micromark-util-subtokenize.mjs +346 -0
  100. package/.output/server/_libs/micromark.mjs +906 -0
  101. package/.output/server/_libs/mimic-function.mjs +47 -0
  102. package/.output/server/_libs/modelcontextprotocol__server.mjs +9738 -0
  103. package/.output/server/_libs/ocache.mjs +1 -0
  104. package/.output/server/_libs/ohash.mjs +1 -0
  105. package/.output/server/_libs/pako.mjs +4223 -0
  106. package/.output/server/_libs/process-nextick-args.mjs +48 -0
  107. package/.output/server/_libs/property-information.mjs +1209 -0
  108. package/.output/server/_libs/radix-ui.mjs +1 -0
  109. package/.output/server/_libs/radix-ui__number.mjs +6 -0
  110. package/.output/server/_libs/radix-ui__primitive.mjs +11 -0
  111. package/.output/server/_libs/radix-ui__react-accordion.mjs +1 -0
  112. package/.output/server/_libs/radix-ui__react-alert-dialog.mjs +1 -0
  113. package/.output/server/_libs/radix-ui__react-arrow.mjs +23 -0
  114. package/.output/server/_libs/radix-ui__react-aspect-ratio.mjs +1 -0
  115. package/.output/server/_libs/radix-ui__react-avatar.mjs +1 -0
  116. package/.output/server/_libs/radix-ui__react-checkbox.mjs +1 -0
  117. package/.output/server/_libs/radix-ui__react-collapsible.mjs +144 -0
  118. package/.output/server/_libs/radix-ui__react-collection.mjs +69 -0
  119. package/.output/server/_libs/radix-ui__react-compose-refs.mjs +39 -0
  120. package/.output/server/_libs/radix-ui__react-context-menu.mjs +1 -0
  121. package/.output/server/_libs/radix-ui__react-context.mjs +78 -0
  122. package/.output/server/_libs/radix-ui__react-dialog.mjs +325 -0
  123. package/.output/server/_libs/radix-ui__react-direction.mjs +9 -0
  124. package/.output/server/_libs/radix-ui__react-dropdown-menu.mjs +1 -0
  125. package/.output/server/_libs/radix-ui__react-focus-guards.mjs +29 -0
  126. package/.output/server/_libs/radix-ui__react-focus-scope.mjs +206 -0
  127. package/.output/server/_libs/radix-ui__react-form.mjs +1 -0
  128. package/.output/server/_libs/radix-ui__react-hover-card.mjs +1 -0
  129. package/.output/server/_libs/radix-ui__react-id.mjs +14 -0
  130. package/.output/server/_libs/radix-ui__react-label.mjs +1 -0
  131. package/.output/server/_libs/radix-ui__react-menu.mjs +1 -0
  132. package/.output/server/_libs/radix-ui__react-menubar.mjs +1 -0
  133. package/.output/server/_libs/radix-ui__react-popover.mjs +1 -0
  134. package/.output/server/_libs/radix-ui__react-popper.mjs +286 -0
  135. package/.output/server/_libs/radix-ui__react-portal.mjs +16 -0
  136. package/.output/server/_libs/radix-ui__react-presence.mjs +128 -0
  137. package/.output/server/_libs/radix-ui__react-primitive.mjs +42 -0
  138. package/.output/server/_libs/radix-ui__react-progress.mjs +1 -0
  139. package/.output/server/_libs/radix-ui__react-radio-group.mjs +1 -0
  140. package/.output/server/_libs/radix-ui__react-roving-focus.mjs +224 -0
  141. package/.output/server/_libs/radix-ui__react-scroll-area.mjs +721 -0
  142. package/.output/server/_libs/radix-ui__react-select.mjs +1163 -0
  143. package/.output/server/_libs/radix-ui__react-separator.mjs +28 -0
  144. package/.output/server/_libs/radix-ui__react-slider.mjs +1 -0
  145. package/.output/server/_libs/radix-ui__react-slot.mjs +99 -0
  146. package/.output/server/_libs/radix-ui__react-switch.mjs +1 -0
  147. package/.output/server/_libs/radix-ui__react-tabs.mjs +189 -0
  148. package/.output/server/_libs/radix-ui__react-toast.mjs +2 -0
  149. package/.output/server/_libs/radix-ui__react-toggle-group.mjs +1 -0
  150. package/.output/server/_libs/radix-ui__react-toggle.mjs +1 -0
  151. package/.output/server/_libs/radix-ui__react-toolbar.mjs +1 -0
  152. package/.output/server/_libs/radix-ui__react-tooltip.mjs +495 -0
  153. package/.output/server/_libs/radix-ui__react-use-previous.mjs +14 -0
  154. package/.output/server/_libs/radix-ui__react-use-size.mjs +39 -0
  155. package/.output/server/_libs/react-dom.mjs +10781 -0
  156. package/.output/server/_libs/react-markdown.mjs +147 -0
  157. package/.output/server/_libs/react-remove-scroll-bar.mjs +82 -0
  158. package/.output/server/_libs/react-remove-scroll.mjs +328 -0
  159. package/.output/server/_libs/react-style-singleton.mjs +69 -0
  160. package/.output/server/_libs/react.mjs +515 -0
  161. package/.output/server/_libs/readable-stream.mjs +1518 -0
  162. package/.output/server/_libs/remark-parse.mjs +19 -0
  163. package/.output/server/_libs/remark-rehype.mjs +21 -0
  164. package/.output/server/_libs/rou3.mjs +14 -0
  165. package/.output/server/_libs/safe-buffer.mjs +64 -0
  166. package/.output/server/_libs/semver.mjs +1938 -0
  167. package/.output/server/_libs/seroval-plugins.mjs +58 -0
  168. package/.output/server/_libs/seroval.mjs +1765 -0
  169. package/.output/server/_libs/setimmediate.mjs +152 -0
  170. package/.output/server/_libs/space-separated-tokens.mjs +6 -0
  171. package/.output/server/_libs/srvx.mjs +1029 -0
  172. package/.output/server/_libs/stubborn-fs.mjs +91 -0
  173. package/.output/server/_libs/stubborn-utils.mjs +66 -0
  174. package/.output/server/_libs/style-to-js.mjs +72 -0
  175. package/.output/server/_libs/style-to-object.mjs +38 -0
  176. package/.output/server/_libs/swr.mjs +939 -0
  177. package/.output/server/_libs/tailwind-merge.mjs +3010 -0
  178. package/.output/server/_libs/tanstack__history.mjs +217 -0
  179. package/.output/server/_libs/tanstack__react-router.mjs +1480 -0
  180. package/.output/server/_libs/tanstack__react-store.mjs +1 -0
  181. package/.output/server/_libs/tanstack__react-virtual.mjs +44 -0
  182. package/.output/server/_libs/tanstack__router-core.mjs +4827 -0
  183. package/.output/server/_libs/tanstack__store.mjs +1 -0
  184. package/.output/server/_libs/tanstack__virtual-core.mjs +1225 -0
  185. package/.output/server/_libs/tiny-invariant.mjs +12 -0
  186. package/.output/server/_libs/tiny-warning.mjs +5 -0
  187. package/.output/server/_libs/trim-lines.mjs +41 -0
  188. package/.output/server/_libs/trough.mjs +85 -0
  189. package/.output/server/_libs/tslib.mjs +1 -0
  190. package/.output/server/_libs/ufo.mjs +54 -0
  191. package/.output/server/_libs/uint8array-extras.mjs +69 -0
  192. package/.output/server/_libs/ungap__structured-clone.mjs +212 -0
  193. package/.output/server/_libs/unified.mjs +661 -0
  194. package/.output/server/_libs/unist-util-is.mjs +100 -0
  195. package/.output/server/_libs/unist-util-position.mjs +27 -0
  196. package/.output/server/_libs/unist-util-stringify-position.mjs +27 -0
  197. package/.output/server/_libs/unist-util-visit-parents.mjs +82 -0
  198. package/.output/server/_libs/unist-util-visit.mjs +24 -0
  199. package/.output/server/_libs/unstorage.mjs +1 -0
  200. package/.output/server/_libs/use-callback-ref.mjs +66 -0
  201. package/.output/server/_libs/use-sidecar.mjs +106 -0
  202. package/.output/server/_libs/use-sync-external-store.mjs +64 -0
  203. package/.output/server/_libs/util-deprecate.mjs +12 -0
  204. package/.output/server/_libs/vfile-message.mjs +138 -0
  205. package/.output/server/_libs/vfile.mjs +467 -0
  206. package/.output/server/_libs/when-exit.mjs +53 -0
  207. package/.output/server/_libs/zod.mjs +4524 -0
  208. package/.output/server/_sessionId-wMLPvC5g.mjs +123 -0
  209. package/.output/server/_ssr/CompareDrawer-BU4V0uVf.mjs +1041 -0
  210. package/.output/server/_ssr/ProxyViewerContainer-BnRwFEnn.mjs +5972 -0
  211. package/.output/server/_ssr/ReplayDialog-C7dn9pd_.mjs +322 -0
  212. package/.output/server/_ssr/RequestAnatomy-C1rWpe9-.mjs +353 -0
  213. package/.output/server/_ssr/ResponseView-hGpPaYsf.mjs +602 -0
  214. package/.output/server/_ssr/StreamingChunkSequence-BRWI1r_G.mjs +302 -0
  215. package/.output/server/_ssr/index-BKURLVPz.mjs +118 -0
  216. package/.output/server/_ssr/index.mjs +1184 -0
  217. package/.output/server/_ssr/json-viewer-BBd2DtQP.mjs +515 -0
  218. package/.output/server/_ssr/router-BcZ0D6AB.mjs +6317 -0
  219. package/.output/server/_ssr/start-HYkvq4Ni.mjs +4 -0
  220. package/.output/server/_tanstack-start-manifest_v-1y8ZVxRI.mjs +4 -0
  221. package/.output/server/index.mjs +436 -0
  222. package/.output/server/node_modules/tslib/modules/index.js +70 -0
  223. package/.output/server/node_modules/tslib/modules/package.json +3 -0
  224. package/.output/server/node_modules/tslib/package.json +47 -0
  225. package/.output/server/node_modules/tslib/tslib.js +484 -0
  226. package/.output/server/package.json +9 -0
  227. package/LICENSE +21 -0
  228. package/README.md +52 -0
  229. package/package.json +110 -0
  230. package/src/assets/favicon.svg +31 -0
  231. package/src/assets/logos/alibaba.svg +1 -0
  232. package/src/assets/logos/anthropic.svg +1 -0
  233. package/src/assets/logos/claude-code.svg +4 -0
  234. package/src/assets/logos/deepseek.svg +1 -0
  235. package/src/assets/logos/mcp.png +0 -0
  236. package/src/assets/logos/minimax.jpeg +0 -0
  237. package/src/assets/logos/openai.svg +1 -0
  238. package/src/assets/logos/opencode.svg +4 -0
  239. package/src/assets/logos/qwen.png +0 -0
  240. package/src/assets/logos/zhipuai.svg +219 -0
  241. package/src/cli/detect-tools.ts +147 -0
  242. package/src/cli/doctor.ts +521 -0
  243. package/src/cli/onboard.ts +224 -0
  244. package/src/cli/templates/command-onboard.ts +17 -0
  245. package/src/cli/templates/skill-onboard.ts +547 -0
  246. package/src/cli.ts +345 -0
  247. package/src/components/OnboardingBanner.tsx +67 -0
  248. package/src/components/ProxyViewer.tsx +545 -0
  249. package/src/components/ProxyViewerContainer.tsx +363 -0
  250. package/src/components/providers/ImportWizardDialog.tsx +349 -0
  251. package/src/components/providers/ProviderCard.tsx +474 -0
  252. package/src/components/providers/ProviderForm.tsx +494 -0
  253. package/src/components/providers/ProviderLogo.tsx +117 -0
  254. package/src/components/providers/ProvidersPanel.tsx +619 -0
  255. package/src/components/providers/SettingsDialog.tsx +202 -0
  256. package/src/components/proxy-viewer/CompareDrawer.tsx +893 -0
  257. package/src/components/proxy-viewer/ConversationGroup.tsx +107 -0
  258. package/src/components/proxy-viewer/ConversationHeader.tsx +300 -0
  259. package/src/components/proxy-viewer/LogEntry.tsx +543 -0
  260. package/src/components/proxy-viewer/LogEntryHeader.tsx +501 -0
  261. package/src/components/proxy-viewer/ReplayDialog.tsx +218 -0
  262. package/src/components/proxy-viewer/ResponseView.tsx +171 -0
  263. package/src/components/proxy-viewer/StreamingChunkSequence.tsx +188 -0
  264. package/src/components/proxy-viewer/ThreadConnector.tsx +136 -0
  265. package/src/components/proxy-viewer/TurnGroup.tsx +337 -0
  266. package/src/components/proxy-viewer/anatomy/RequestAnatomy.tsx +98 -0
  267. package/src/components/proxy-viewer/anatomy/SegmentBar.tsx +196 -0
  268. package/src/components/proxy-viewer/anatomy/tokenEstimate.ts +53 -0
  269. package/src/components/proxy-viewer/anatomy/types.ts +39 -0
  270. package/src/components/proxy-viewer/anatomy/useAnatomyJump.ts +114 -0
  271. package/src/components/proxy-viewer/cacheTrend.ts +50 -0
  272. package/src/components/proxy-viewer/diff/DiffView.tsx +321 -0
  273. package/src/components/proxy-viewer/diff/computeDiff.ts +178 -0
  274. package/src/components/proxy-viewer/diff/index.ts +3 -0
  275. package/src/components/proxy-viewer/formats/anthropic/ContentBlocks.tsx +157 -0
  276. package/src/components/proxy-viewer/formats/anthropic/ResponseView.tsx +66 -0
  277. package/src/components/proxy-viewer/formats/anthropic/thinkingExtract.ts +21 -0
  278. package/src/components/proxy-viewer/formats/index.tsx +33 -0
  279. package/src/components/proxy-viewer/formats/openai/ResponseView.tsx +170 -0
  280. package/src/components/proxy-viewer/index.ts +9 -0
  281. package/src/components/proxy-viewer/lazy.ts +37 -0
  282. package/src/components/proxy-viewer/log-formats/anthropic.ts +194 -0
  283. package/src/components/proxy-viewer/log-formats/index.ts +23 -0
  284. package/src/components/proxy-viewer/log-formats/openai.ts +167 -0
  285. package/src/components/proxy-viewer/log-formats/types.ts +40 -0
  286. package/src/components/proxy-viewer/log-formats/unknown.ts +18 -0
  287. package/src/components/proxy-viewer/logEntryVisibility.ts +39 -0
  288. package/src/components/proxy-viewer/requestDiff.ts +277 -0
  289. package/src/components/proxy-viewer/useCopyFeedback.ts +36 -0
  290. package/src/components/proxy-viewer/useKeyboardNavigation.ts +190 -0
  291. package/src/components/proxy-viewer/viewerState.ts +66 -0
  292. package/src/components/ui/badge.tsx +47 -0
  293. package/src/components/ui/button.tsx +47 -0
  294. package/src/components/ui/collapsible.tsx +21 -0
  295. package/src/components/ui/confirm-dialog.tsx +51 -0
  296. package/src/components/ui/crab-logo.tsx +95 -0
  297. package/src/components/ui/crab-variants.tsx +467 -0
  298. package/src/components/ui/dialog.tsx +129 -0
  299. package/src/components/ui/json-expansion-button.tsx +56 -0
  300. package/src/components/ui/json-viewer-bulk.ts +97 -0
  301. package/src/components/ui/json-viewer.tsx +494 -0
  302. package/src/components/ui/mcp-logo.tsx +20 -0
  303. package/src/components/ui/scroll-area.tsx +54 -0
  304. package/src/components/ui/select.tsx +178 -0
  305. package/src/components/ui/separator.tsx +28 -0
  306. package/src/components/ui/tabs.tsx +88 -0
  307. package/src/components/ui/tooltip.tsx +51 -0
  308. package/src/index.css +11 -0
  309. package/src/knowledge/candidateStore.ts +63 -0
  310. package/src/knowledge/distiller.ts +98 -0
  311. package/src/knowledge/openclawClient.ts +118 -0
  312. package/src/knowledge/redactor.ts +80 -0
  313. package/src/knowledge/types.ts +84 -0
  314. package/src/lib/apiClient.ts +49 -0
  315. package/src/lib/export-logs.ts +51 -0
  316. package/src/lib/mask.ts +4 -0
  317. package/src/lib/objectUtils.ts +22 -0
  318. package/src/lib/providerContract.ts +26 -0
  319. package/src/lib/providerTestContract.ts +107 -0
  320. package/src/lib/runtimeConfig.ts +25 -0
  321. package/src/lib/serverPort.ts +41 -0
  322. package/src/lib/sessionUrl.ts +44 -0
  323. package/src/lib/stopReason.ts +58 -0
  324. package/src/lib/useOnboarding.ts +80 -0
  325. package/src/lib/useProviders.ts +30 -0
  326. package/src/lib/useStripConfig.ts +108 -0
  327. package/src/lib/utils.ts +21 -0
  328. package/src/mcp/loopback.ts +76 -0
  329. package/src/mcp/previewExtractor.ts +166 -0
  330. package/src/mcp/server.ts +396 -0
  331. package/src/mcp/toolHandlers.ts +341 -0
  332. package/src/proxy/chunkStorage.ts +112 -0
  333. package/src/proxy/claudeCodeStrip.ts +99 -0
  334. package/src/proxy/config.ts +172 -0
  335. package/src/proxy/constants.ts +47 -0
  336. package/src/proxy/dataDir.ts +86 -0
  337. package/src/proxy/formats/anthropic/anthropicProvider.ts +75 -0
  338. package/src/proxy/formats/anthropic/handler.ts +71 -0
  339. package/src/proxy/formats/anthropic/index.ts +14 -0
  340. package/src/proxy/formats/anthropic/register.ts +4 -0
  341. package/src/proxy/formats/anthropic/schemas.ts +237 -0
  342. package/src/proxy/formats/anthropic/stream.ts +205 -0
  343. package/src/proxy/formats/handler.ts +46 -0
  344. package/src/proxy/formats/index.ts +12 -0
  345. package/src/proxy/formats/jsonSchema.ts +36 -0
  346. package/src/proxy/formats/openai/alibabaProvider.ts +38 -0
  347. package/src/proxy/formats/openai/handler.ts +96 -0
  348. package/src/proxy/formats/openai/index.ts +25 -0
  349. package/src/proxy/formats/openai/provider.ts +50 -0
  350. package/src/proxy/formats/openai/register.ts +4 -0
  351. package/src/proxy/formats/openai/schemas.ts +187 -0
  352. package/src/proxy/formats/openai/stream.ts +206 -0
  353. package/src/proxy/formats/protocol.ts +50 -0
  354. package/src/proxy/formats/providerRegistry.ts +51 -0
  355. package/src/proxy/formats/providers/index.ts +3 -0
  356. package/src/proxy/formats/registry.ts +66 -0
  357. package/src/proxy/handler.ts +334 -0
  358. package/src/proxy/logFinalizer.ts +305 -0
  359. package/src/proxy/logFinalizer.worker.ts +24 -0
  360. package/src/proxy/logIndex.ts +268 -0
  361. package/src/proxy/logger.ts +179 -0
  362. package/src/proxy/openaiOrphanToolStrip.ts +142 -0
  363. package/src/proxy/providerImporters.ts +491 -0
  364. package/src/proxy/providers.ts +613 -0
  365. package/src/proxy/schemas.ts +209 -0
  366. package/src/proxy/sessionProcess.ts +140 -0
  367. package/src/proxy/sessionRuntime.ts +85 -0
  368. package/src/proxy/sessionSupervisor.ts +283 -0
  369. package/src/proxy/sessionWorkerEntry.ts +26 -0
  370. package/src/proxy/socketTracker.ts +255 -0
  371. package/src/proxy/store.ts +412 -0
  372. package/src/proxy/upstream.ts +90 -0
  373. package/src/router.tsx +16 -0
  374. package/src/routes/__root.tsx +45 -0
  375. package/src/routes/api/config.paths.ts +14 -0
  376. package/src/routes/api/config.ts +53 -0
  377. package/src/routes/api/health.ts +15 -0
  378. package/src/routes/api/knowledge.candidates.$candidateId.promote.ts +32 -0
  379. package/src/routes/api/knowledge.candidates.ts +10 -0
  380. package/src/routes/api/knowledge.project-context.ts +18 -0
  381. package/src/routes/api/knowledge.search.ts +31 -0
  382. package/src/routes/api/knowledge.sessions.$sessionId.candidates.ts +16 -0
  383. package/src/routes/api/logs.$id.chunks.ts +36 -0
  384. package/src/routes/api/logs.$id.replay.ts +191 -0
  385. package/src/routes/api/logs.$id.ts +22 -0
  386. package/src/routes/api/logs.stream.ts +74 -0
  387. package/src/routes/api/logs.ts +59 -0
  388. package/src/routes/api/mcp.ts +25 -0
  389. package/src/routes/api/models.ts +10 -0
  390. package/src/routes/api/providers.$providerId.test.log.ts +293 -0
  391. package/src/routes/api/providers.$providerId.ts +50 -0
  392. package/src/routes/api/providers.export.ts +26 -0
  393. package/src/routes/api/providers.import.ts +47 -0
  394. package/src/routes/api/providers.scan.ts +23 -0
  395. package/src/routes/api/providers.ts +45 -0
  396. package/src/routes/api/sessions.ts +17 -0
  397. package/src/routes/index.tsx +6 -0
  398. package/src/routes/proxy/$.ts +15 -0
  399. package/src/routes/session/$sessionId.tsx +23 -0
  400. package/styles/globals.css +188 -0
@@ -0,0 +1,218 @@
1
+ import { RotateCcw } from "lucide-react";
2
+ import type { JSX } from "react";
3
+ import { useState } from "react";
4
+ import { z } from "zod";
5
+ import { Button } from "../ui/button";
6
+ import { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } from "../ui/tooltip";
7
+ import { Dialog, DialogContent, DialogHeader, DialogTitle } from "../ui/dialog";
8
+ import { Tabs, TabsContent, TabsList, TabsTrigger } from "../ui/tabs";
9
+ import { ResponseView } from "./ResponseView";
10
+ import type { CapturedLog } from "../../proxy/schemas";
11
+
12
+ const ReplayResultSchema = z.object({
13
+ success: z.boolean(),
14
+ error: z.string().optional(),
15
+ responseStatus: z.number().optional(),
16
+ responseText: z.string().optional(),
17
+ inputTokens: z.number().optional(),
18
+ outputTokens: z.number().optional(),
19
+ elapsedMs: z.number().optional(),
20
+ streaming: z.boolean().optional(),
21
+ });
22
+
23
+ type ReplayResult = z.infer<typeof ReplayResultSchema>;
24
+
25
+ type ReplayDialogProps = {
26
+ log: CapturedLog;
27
+ open: boolean;
28
+ onOpenChange: (open: boolean) => void;
29
+ };
30
+
31
+ export function ReplayDialog({ log, open, onOpenChange }: ReplayDialogProps): JSX.Element {
32
+ const [modifiedBody, setModifiedBody] = useState<string>(() => {
33
+ return log.rawRequestBody ?? "{}";
34
+ });
35
+ const [replayResult, setReplayResult] = useState<ReplayResult | null>(null);
36
+ const [loading, setLoading] = useState(false);
37
+ const [error, setError] = useState<string | null>(null);
38
+
39
+ async function handleReplay() {
40
+ setLoading(true);
41
+ setError(null);
42
+ setReplayResult(null);
43
+
44
+ try {
45
+ const res = await fetch(`/api/logs/${log.id}/replay`, {
46
+ method: "POST",
47
+ headers: { "Content-Type": "application/json" },
48
+ body: JSON.stringify({ modifiedBody }),
49
+ });
50
+
51
+ const json: unknown = await res.json();
52
+ const parsed = ReplayResultSchema.safeParse(json);
53
+ if (!parsed.success) {
54
+ setError("Invalid response from server");
55
+ setLoading(false);
56
+ return;
57
+ }
58
+ const data = parsed.data;
59
+ setReplayResult(data);
60
+ if (!data.success) {
61
+ setError(data.error ?? "Replay failed");
62
+ }
63
+ } catch (err) {
64
+ setError(err instanceof Error ? err.message : "Network error");
65
+ } finally {
66
+ setLoading(false);
67
+ }
68
+ }
69
+
70
+ function handleClose() {
71
+ setReplayResult(null);
72
+ setError(null);
73
+ onOpenChange(false);
74
+ }
75
+
76
+ return (
77
+ <Dialog open={open} onOpenChange={handleClose}>
78
+ <DialogContent className="max-w-4xl max-h-[85vh] overflow-auto">
79
+ <DialogHeader>
80
+ <DialogTitle className="flex items-center gap-2">
81
+ <RotateCcw className="size-4" />
82
+ Replay Request #{log.id}
83
+ </DialogTitle>
84
+ </DialogHeader>
85
+
86
+ <Tabs defaultValue="modified">
87
+ <TabsList>
88
+ <TabsTrigger value="modified">Modified Request</TabsTrigger>
89
+ <TabsTrigger value="original">Original Response</TabsTrigger>
90
+ {replayResult && <TabsTrigger value="replay">Replay Response</TabsTrigger>}
91
+ </TabsList>
92
+
93
+ <TabsContent value="modified" className="space-y-4">
94
+ <div>
95
+ <label className="text-sm font-medium mb-2 block">Request Body (JSON)</label>
96
+ <TooltipProvider>
97
+ <Tooltip>
98
+ <TooltipTrigger asChild>
99
+ <textarea
100
+ className="w-full h-64 p-3 font-mono text-xs bg-muted rounded-md border border-input resize-none focus:outline-none focus:ring-2 focus:ring-ring"
101
+ value={modifiedBody}
102
+ onChange={(e) => setModifiedBody(e.target.value)}
103
+ spellCheck={false}
104
+ />
105
+ </TooltipTrigger>
106
+ <TooltipContent>
107
+ Edit the request body before re-sending to the provider
108
+ </TooltipContent>
109
+ </Tooltip>
110
+ </TooltipProvider>
111
+ </div>
112
+
113
+ {error !== null && error !== "" && (
114
+ <div className="text-sm text-destructive bg-destructive/10 px-3 py-2 rounded-md">
115
+ {error}
116
+ </div>
117
+ )}
118
+
119
+ <div className="flex justify-end">
120
+ <Button
121
+ onClick={() => {
122
+ void handleReplay();
123
+ }}
124
+ disabled={loading}
125
+ >
126
+ {loading ? "Replaying..." : "Replay"}
127
+ </Button>
128
+ </div>
129
+
130
+ {replayResult && replayResult.success && (
131
+ <Tabs defaultValue="parsed">
132
+ <TabsList>
133
+ <TabsTrigger value="parsed">Response</TabsTrigger>
134
+ <TabsTrigger value="raw">Raw Response</TabsTrigger>
135
+ </TabsList>
136
+ <TabsContent value="parsed">
137
+ <ResponseView
138
+ responseText={replayResult.responseText ?? null}
139
+ responseStatus={replayResult.responseStatus ?? null}
140
+ streaming={replayResult.streaming ?? false}
141
+ inputTokens={replayResult.inputTokens ?? null}
142
+ outputTokens={replayResult.outputTokens ?? null}
143
+ apiFormat={log.apiFormat}
144
+ />
145
+ </TabsContent>
146
+ <TabsContent value="raw">
147
+ <pre className="font-mono text-xs whitespace-pre-wrap bg-muted p-3 rounded-md max-h-96 overflow-auto">
148
+ {replayResult.responseText ?? "No response"}
149
+ </pre>
150
+ </TabsContent>
151
+ </Tabs>
152
+ )}
153
+ </TabsContent>
154
+
155
+ <TabsContent value="original">
156
+ {log.responseText !== null ? (
157
+ <Tabs defaultValue="parsed">
158
+ <TabsList>
159
+ <TabsTrigger value="parsed">Response</TabsTrigger>
160
+ <TabsTrigger value="raw">Raw Response</TabsTrigger>
161
+ </TabsList>
162
+ <TabsContent value="parsed">
163
+ <ResponseView
164
+ responseText={log.responseText}
165
+ responseStatus={log.responseStatus}
166
+ streaming={log.streaming}
167
+ inputTokens={log.inputTokens}
168
+ outputTokens={log.outputTokens}
169
+ cacheCreationInputTokens={log.cacheCreationInputTokens}
170
+ cacheReadInputTokens={log.cacheReadInputTokens}
171
+ apiFormat={log.apiFormat}
172
+ />
173
+ </TabsContent>
174
+ <TabsContent value="raw">
175
+ <pre className="font-mono text-xs whitespace-pre-wrap bg-muted p-3 rounded-md max-h-96 overflow-auto">
176
+ {log.responseText}
177
+ </pre>
178
+ </TabsContent>
179
+ </Tabs>
180
+ ) : (
181
+ <p className="text-sm text-muted-foreground italic">No original response</p>
182
+ )}
183
+ </TabsContent>
184
+
185
+ {replayResult && replayResult.success && (
186
+ <TabsContent value="replay">
187
+ {replayResult.responseText !== null ? (
188
+ <Tabs defaultValue="parsed">
189
+ <TabsList>
190
+ <TabsTrigger value="parsed">Response</TabsTrigger>
191
+ <TabsTrigger value="raw">Raw Response</TabsTrigger>
192
+ </TabsList>
193
+ <TabsContent value="parsed">
194
+ <ResponseView
195
+ responseText={replayResult.responseText ?? null}
196
+ responseStatus={replayResult.responseStatus ?? null}
197
+ streaming={replayResult.streaming ?? false}
198
+ inputTokens={replayResult.inputTokens ?? null}
199
+ outputTokens={replayResult.outputTokens ?? null}
200
+ apiFormat={log.apiFormat}
201
+ />
202
+ </TabsContent>
203
+ <TabsContent value="raw">
204
+ <pre className="font-mono text-xs whitespace-pre-wrap bg-muted p-3 rounded-md max-h-96 overflow-auto">
205
+ {replayResult.responseText}
206
+ </pre>
207
+ </TabsContent>
208
+ </Tabs>
209
+ ) : (
210
+ <p className="text-sm text-muted-foreground italic">No replay response</p>
211
+ )}
212
+ </TabsContent>
213
+ )}
214
+ </Tabs>
215
+ </DialogContent>
216
+ </Dialog>
217
+ );
218
+ }
@@ -0,0 +1,171 @@
1
+ import { AlertTriangle, Zap } from "lucide-react";
2
+ import type { JSX } from "react";
3
+ import { memo } from "react";
4
+ import { useMemo } from "react";
5
+ import ReactMarkdown from "react-markdown";
6
+ import { cn, formatTokens, getStatusCategory, type StatusCategory } from "../../lib/utils";
7
+ import type { RequestFormat } from "../../proxy/schemas";
8
+ import { formatViewFor } from "./formats";
9
+ import { getLogFormatAdapter } from "./log-formats";
10
+
11
+ export type ResponseViewProps = {
12
+ responseText: string | null;
13
+ responseStatus: number | null;
14
+ streaming: boolean;
15
+ inputTokens: number | null;
16
+ outputTokens: number | null;
17
+ cacheCreationInputTokens?: number | null;
18
+ cacheReadInputTokens?: number | null;
19
+ apiFormat?: RequestFormat;
20
+ /** SSE error message from streaming response */
21
+ error?: string | null;
22
+ };
23
+
24
+ function getStatusClasses(category: StatusCategory): string {
25
+ switch (category) {
26
+ case "success":
27
+ return "text-emerald-400";
28
+ case "client_error":
29
+ return "text-amber-400";
30
+ case "server_error":
31
+ return "text-red-400";
32
+ case "pending":
33
+ return "text-muted-foreground";
34
+ }
35
+ }
36
+
37
+ function StatusIndicator({ status }: { status: number | null }): JSX.Element {
38
+ const category = getStatusCategory(status);
39
+ const classes = getStatusClasses(category);
40
+
41
+ if (status === null) {
42
+ return <span className="text-xs text-muted-foreground italic">pending</span>;
43
+ }
44
+
45
+ return (
46
+ <span className={cn("flex items-center gap-1 text-xs font-mono font-semibold", classes)}>
47
+ {category === "server_error" && <AlertTriangle className="size-3" />}
48
+ {status}
49
+ </span>
50
+ );
51
+ }
52
+
53
+ function ErrorResponseView({ text }: { text: string }): JSX.Element {
54
+ return (
55
+ <div className="rounded-md border border-red-500/30 bg-red-500/5 p-3">
56
+ <pre className="text-xs text-red-300 whitespace-pre-wrap font-mono leading-relaxed overflow-auto max-h-[60vh]">
57
+ {text}
58
+ </pre>
59
+ </div>
60
+ );
61
+ }
62
+
63
+ function MarkdownFallbackView({ text }: { text: string }): JSX.Element {
64
+ return (
65
+ <div className="prose prose-sm dark:prose-invert max-w-none [&_pre]:bg-muted [&_pre]:text-foreground [&_code]:text-[0.8em] [&_p]:my-1 [&_ul]:my-1 [&_ol]:my-1">
66
+ <ReactMarkdown>{text}</ReactMarkdown>
67
+ </div>
68
+ );
69
+ }
70
+
71
+ export const ResponseView = memo(function ResponseView({
72
+ responseText,
73
+ responseStatus,
74
+ streaming,
75
+ inputTokens,
76
+ outputTokens,
77
+ cacheCreationInputTokens,
78
+ cacheReadInputTokens,
79
+ apiFormat,
80
+ error,
81
+ }: ResponseViewProps): JSX.Element {
82
+ const resolvedFormat = apiFormat ?? "unknown";
83
+ const parsed = useMemo(
84
+ () => getLogFormatAdapter(resolvedFormat).analyzeResponse(responseText).parsed,
85
+ [resolvedFormat, responseText],
86
+ );
87
+
88
+ if (responseText === null && error === undefined) {
89
+ return (
90
+ <div className="flex items-center gap-2 py-3">
91
+ <StatusIndicator status={responseStatus} />
92
+ <span className="text-xs text-muted-foreground italic">No response</span>
93
+ </div>
94
+ );
95
+ }
96
+
97
+ const isHttpError = responseStatus !== null && responseStatus >= 400;
98
+
99
+ if (isHttpError) {
100
+ return (
101
+ <div className="space-y-2">
102
+ <StatusIndicator status={responseStatus} />
103
+ <ErrorResponseView text={responseText ?? ""} />
104
+ {error !== undefined && error !== null && (
105
+ <div className="rounded border border-destructive/50 bg-destructive/10 p-3 text-xs">
106
+ <div className="font-semibold text-destructive mb-1">SSE Error</div>
107
+ <div className="text-muted-foreground font-mono">{error}</div>
108
+ </div>
109
+ )}
110
+ </div>
111
+ );
112
+ }
113
+
114
+ if (error !== undefined && error !== null) {
115
+ return (
116
+ <div className="space-y-2">
117
+ <StatusIndicator status={responseStatus} />
118
+ <div className="rounded border border-destructive/50 bg-destructive/10 p-3 text-xs">
119
+ <div className="font-semibold text-destructive mb-1">SSE Error</div>
120
+ <div className="text-muted-foreground font-mono">{error}</div>
121
+ </div>
122
+ {responseText !== null && (
123
+ <div className="mt-2">
124
+ <ErrorResponseView text={responseText} />
125
+ </div>
126
+ )}
127
+ </div>
128
+ );
129
+ }
130
+
131
+ if (parsed !== null) {
132
+ return (
133
+ <div className="space-y-2">
134
+ <StatusIndicator status={responseStatus} />
135
+ {formatViewFor(resolvedFormat, parsed)}
136
+ </div>
137
+ );
138
+ }
139
+
140
+ return (
141
+ <div className="space-y-2">
142
+ <div className="flex items-center gap-2">
143
+ <StatusIndicator status={responseStatus} />
144
+ {streaming && (inputTokens !== null || outputTokens !== null) && (
145
+ <span className="flex items-center gap-1 text-muted-foreground text-xs">
146
+ <Zap className="size-3" />
147
+ <span className="font-mono tabular-nums">
148
+ {inputTokens !== null ? formatTokens(inputTokens) : "—"} in /{" "}
149
+ {outputTokens !== null ? formatTokens(outputTokens) : "—"} out
150
+ </span>
151
+ {cacheCreationInputTokens !== null &&
152
+ cacheCreationInputTokens !== undefined &&
153
+ cacheCreationInputTokens > 0 && (
154
+ <span className="font-mono tabular-nums text-emerald-400">
155
+ Cache +{formatTokens(cacheCreationInputTokens)}
156
+ </span>
157
+ )}
158
+ {cacheReadInputTokens !== null &&
159
+ cacheReadInputTokens !== undefined &&
160
+ cacheReadInputTokens > 0 && (
161
+ <span className="font-mono tabular-nums text-purple-400">
162
+ Cache ~{formatTokens(cacheReadInputTokens)}
163
+ </span>
164
+ )}
165
+ </span>
166
+ )}
167
+ </div>
168
+ <MarkdownFallbackView text={responseText ?? ""} />
169
+ </div>
170
+ );
171
+ });
@@ -0,0 +1,188 @@
1
+ import { memo, useState, useEffect, useMemo, type JSX } from "react";
2
+ import { ChevronDown, ChevronRight, Loader2 } from "lucide-react";
3
+ import { Badge } from "../ui/badge";
4
+ import { JsonViewer } from "../ui/json-viewer";
5
+ import { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } from "../ui/tooltip";
6
+ import type { StreamingChunk } from "../../proxy/schemas";
7
+
8
+ export type StreamingChunkSequenceProps = {
9
+ logId: number;
10
+ truncated?: boolean;
11
+ };
12
+
13
+ type ChunkState =
14
+ | { status: "idle" }
15
+ | { status: "loading" }
16
+ | { status: "success"; chunks: StreamingChunk[] }
17
+ | { status: "error"; message: string };
18
+
19
+ type ChunkGroup = {
20
+ index: number;
21
+ chunks: StreamingChunk[];
22
+ };
23
+
24
+ export const StreamingChunkSequence = memo(function StreamingChunkSequence({
25
+ logId,
26
+ truncated,
27
+ }: StreamingChunkSequenceProps): JSX.Element {
28
+ const [containerExpanded, setContainerExpanded] = useState(false);
29
+ const [chunkState, setChunkState] = useState<ChunkState>({ status: "idle" });
30
+ const [expandedIndices, setExpandedIndices] = useState<Set<number>>(new Set());
31
+
32
+ useEffect(() => {
33
+ if (!containerExpanded || chunkState.status !== "idle") return;
34
+
35
+ let cancelled = false;
36
+ setChunkState({ status: "loading" });
37
+
38
+ fetch(`/api/logs/${logId}/chunks`)
39
+ .then((res) => {
40
+ if (!res.ok) {
41
+ return Promise.reject(new Error("Chunks not found"));
42
+ }
43
+ return res.json();
44
+ })
45
+ .then((data: { chunks: StreamingChunk[]; truncated?: boolean }) => {
46
+ if (!cancelled) {
47
+ setChunkState({ status: "success", chunks: data.chunks });
48
+ }
49
+ })
50
+ .catch(() => {
51
+ if (!cancelled) {
52
+ setChunkState({ status: "error", message: "Chunk data unavailable" });
53
+ }
54
+ });
55
+
56
+ return () => {
57
+ cancelled = true;
58
+ };
59
+ }, [containerExpanded, logId]);
60
+
61
+ const groups = useMemo<ChunkGroup[]>(() => {
62
+ if (chunkState.status !== "success") return [];
63
+
64
+ const map = new Map<number, StreamingChunk[]>();
65
+ for (const chunk of chunkState.chunks) {
66
+ const existing = map.get(chunk.index);
67
+ if (existing) {
68
+ existing.push(chunk);
69
+ } else {
70
+ map.set(chunk.index, [chunk]);
71
+ }
72
+ }
73
+
74
+ return Array.from(map.entries())
75
+ .map(([index, chunks]) => ({ index, chunks }))
76
+ .sort((a, b) => a.index - b.index);
77
+ }, [chunkState]);
78
+
79
+ const toggleIndex = (index: number) => {
80
+ setExpandedIndices((prev) => {
81
+ const next = new Set(prev);
82
+ if (next.has(index)) {
83
+ next.delete(index);
84
+ } else {
85
+ next.add(index);
86
+ }
87
+ return next;
88
+ });
89
+ };
90
+
91
+ function renderBody(): JSX.Element {
92
+ if (chunkState.status === "idle" || chunkState.status === "loading") {
93
+ return (
94
+ <div className="flex items-center gap-2 py-2 text-xs text-muted-foreground">
95
+ <Loader2 className="size-3 animate-spin" />
96
+ <span>Loading chunks...</span>
97
+ </div>
98
+ );
99
+ }
100
+
101
+ if (chunkState.status === "error") {
102
+ return <div className="py-2 text-xs text-muted-foreground italic">{chunkState.message}</div>;
103
+ }
104
+
105
+ return (
106
+ <div className="p-2 space-y-1">
107
+ <div className="text-[10px] text-muted-foreground font-mono mb-2">
108
+ {groups.length} index group{groups.length !== 1 ? "s" : ""} available
109
+ </div>
110
+ {groups.map((group) => {
111
+ const isExpanded = expandedIndices.has(group.index);
112
+ return (
113
+ <div key={group.index} className="rounded border border-border bg-background">
114
+ <button
115
+ type="button"
116
+ className="flex items-center gap-2 w-full px-2 py-1.5 text-left hover:bg-muted/50 transition-colors cursor-pointer"
117
+ onClick={() => toggleIndex(group.index)}
118
+ >
119
+ {isExpanded ? (
120
+ <ChevronDown className="size-3 text-muted-foreground" />
121
+ ) : (
122
+ <ChevronRight className="size-3 text-muted-foreground" />
123
+ )}
124
+ <span className="text-[10px] text-muted-foreground font-mono">
125
+ [{group.index}] {group.chunks[0]?.type ?? ""}
126
+ </span>
127
+ <span className="text-[10px] text-muted-foreground font-mono">
128
+ {group.chunks.length} chunk{group.chunks.length !== 1 ? "s" : ""}
129
+ </span>
130
+ </button>
131
+ {isExpanded && (
132
+ <div className="px-2 pb-2 space-y-1">
133
+ {group.chunks.map((chunk) => (
134
+ <div key={chunk.index} className="rounded border border-border bg-muted/20 p-2">
135
+ <div className="flex items-center gap-2 mb-1">
136
+ <span className="text-[10px] text-muted-foreground font-mono">
137
+ +{chunk.timestamp}ms
138
+ </span>
139
+ <span className="text-[10px] text-muted-foreground font-mono">
140
+ {chunk.type}
141
+ </span>
142
+ </div>
143
+ <JsonViewer data={chunk} defaultExpandDepth={0} showCopy />
144
+ </div>
145
+ ))}
146
+ </div>
147
+ )}
148
+ </div>
149
+ );
150
+ })}
151
+ </div>
152
+ );
153
+ }
154
+
155
+ return (
156
+ <div className="space-y-1">
157
+ <TooltipProvider>
158
+ <Tooltip>
159
+ <TooltipTrigger asChild>
160
+ <button
161
+ type="button"
162
+ className="flex items-center gap-1.5 text-xs text-muted-foreground hover:text-foreground transition-colors cursor-pointer"
163
+ onClick={() => setContainerExpanded((v) => !v)}
164
+ >
165
+ {containerExpanded ? (
166
+ <ChevronDown className="size-3" />
167
+ ) : (
168
+ <ChevronRight className="size-3" />
169
+ )}
170
+ <span>Raw SSE Events</span>
171
+ <Badge variant="outline" className="text-[9px] px-1 py-0 h-4 font-mono ml-1">
172
+ {logId}
173
+ {truncated === true ? "+" : ""}
174
+ </Badge>
175
+ </button>
176
+ </TooltipTrigger>
177
+ <TooltipContent>Server-Sent Events streaming chunks from the provider</TooltipContent>
178
+ </Tooltip>
179
+ </TooltipProvider>
180
+
181
+ {containerExpanded === true ? (
182
+ <div className="rounded-md border border-border bg-muted/20 overflow-auto max-h-64">
183
+ {renderBody()}
184
+ </div>
185
+ ) : null}
186
+ </div>
187
+ );
188
+ });