mirror of
https://github.com/bytedance/deer-flow.git
synced 2026-07-27 00:17:53 +00:00
fix(frontend): prevent streamed word animation replay (#4266)
* fix(frontend): stop replaying streamed word animations * fix(frontend): restore Streamdown rendering plugins --------- Co-authored-by: Willem Jiang <willem.jiang@gmail.com>
This commit is contained in:
parent
6549fffd0e
commit
bb0088127b
@ -684,6 +684,8 @@ The Web UI composer also supports browser-based voice dictation when the browser
|
||||
|
||||
Interrupted first-turn runs still persist a fallback conversation title, so stopping a streaming response does not leave the thread as "Untitled" after refresh.
|
||||
|
||||
Streaming Markdown responses animate only newly arrived words; text that is already visible is not faded out and replayed when the next chunk extends the same block.
|
||||
|
||||
In the Web UI, completed assistant turns can be branched into a new main conversation. The new thread starts from that turn's checkpoint. Because workspace files are not checkpointed, the branch only receives a best-effort copy of the current workspace when you branch from the latest turn; branching from an older turn keeps just the restored message history so the branch never inherits files that were created in a later part of the conversation.
|
||||
|
||||
Web UI chat links percent-encode custom thread identifiers before placing them in route segments, so reserved URL characters such as `#` and `?` do not change which conversation is opened.
|
||||
|
||||
@ -86,6 +86,7 @@ Tool-calling AI messages can contain user-visible text as well as `tool_calls`.
|
||||
- **Thread hooks** (`useThreadStream`, `useSubmitThread`, `useThreads`) are the primary API interface
|
||||
- **Thread routes** — construct Web UI chat paths through `core/threads/utils.ts::pathOfThread()`, which percent-encodes both custom agent names and thread IDs before inserting them into route segments
|
||||
- **LangGraph client** is a singleton obtained via `getAPIClient()` in `core/api/`
|
||||
- **Streaming Markdown rendering** is owned by `core/streamdown`: Streamdown's `animated` / `isAnimating` API handles incremental word animation, while the shared `streamdownRenderingPlugins` config registers the named code-highlighting and Mermaid plugins required by Streamdown 2.5. Keep wrappers and derived configs wired to that shared object; do not reintroduce a rehype plugin that wraps every word, because reparsing a growing block remounts old words and replays their animation.
|
||||
- **Environment validation** uses `@t3-oss/env-nextjs` with Zod schemas (`src/env.js`). Skip with `SKIP_ENV_VALIDATION=1`
|
||||
- **Subtask step history and runtime metadata** (`core/tasks/`) — the subtask card shows a subagent's full step timeline (#3779): its assistant reasoning turns interleaved with the tools it ran. `Subtask.steps[]` is accumulated live from `task_running` events (appended via `mergeSteps`, not overwritten) and backfilled on expand for historical runs by `fetchSubtaskSteps`, which pages the events endpoint scoped to one task (GET `/runs/{runId}/events?event_types=subagent.step&task_id=…&after_seq=…`) until a short page, so the run-wide limit can't truncate the timeline. `task_started` carries the effective `model_name`; `task_running` carries a cumulative usage snapshot after each completed LLM call. `core/tasks/lifecycle.ts` normalizes these additive events, and `computeNextSubtask` keeps the largest cumulative total so replayed or late SSE frames cannot double-count or roll the folded card backward. Terminal ToolMessage metadata (`subagent_model_name` / `subagent_token_usage`) restores the same values from normal history after reload; no per-card event fetch is needed. `core/tasks/steps.ts` is the pure step model: `messageToStep` (live), `eventsToSteps` (reload), `mergeSteps` (dedup by `message_index`), and `stepsForDisplay` (what the card renders — keeps tool steps + AI steps with text, drops the trailing final-answer AI step when completed since it's shown as `result`). `core/tasks/context.tsx`'s `useUpdateSubtask` applies updates against a `tasksRef` mirroring the latest state (not a closure snapshot), so a late-resolving `fetchSubtaskSteps` backfill merges into current state instead of clobbering SSE steps or sibling subtasks that arrived meanwhile. The owning `run_id` is carried onto history content messages in `buildVisibleHistoryMessages` so the card can resolve the events endpoint.
|
||||
|
||||
|
||||
@ -45,6 +45,8 @@
|
||||
"@radix-ui/react-toggle-group": "^1.1.11",
|
||||
"@radix-ui/react-tooltip": "^1.2.8",
|
||||
"@radix-ui/react-use-controllable-state": "^1.2.2",
|
||||
"@streamdown/code": "1.1.1",
|
||||
"@streamdown/mermaid": "1.0.2",
|
||||
"@t3-oss/env-nextjs": "^0.12.0",
|
||||
"@tanstack/react-query": "^5.90.17",
|
||||
"@types/hast": "^3.0.4",
|
||||
@ -84,9 +86,9 @@
|
||||
"rehype-slug": "^6.0.0",
|
||||
"remark-gfm": "^4.0.1",
|
||||
"remark-math": "^6.0.0",
|
||||
"shiki": "3.15.0",
|
||||
"shiki": "3.23.0",
|
||||
"sonner": "^2.0.7",
|
||||
"streamdown": "1.4.0",
|
||||
"streamdown": "2.5.0",
|
||||
"tailwind-merge": "^3.4.0",
|
||||
"tokenlens": "^1.3.1",
|
||||
"unist-util-visit": "^5.0.0",
|
||||
|
||||
272
frontend/pnpm-lock.yaml
generated
272
frontend/pnpm-lock.yaml
generated
@ -86,6 +86,12 @@ importers:
|
||||
'@radix-ui/react-use-controllable-state':
|
||||
specifier: ^1.2.2
|
||||
version: 1.2.2(@types/react@19.2.13)(react@19.2.4)
|
||||
'@streamdown/code':
|
||||
specifier: 1.1.1
|
||||
version: 1.1.1(react@19.2.4)
|
||||
'@streamdown/mermaid':
|
||||
specifier: 1.0.2
|
||||
version: 1.0.2(react@19.2.4)
|
||||
'@t3-oss/env-nextjs':
|
||||
specifier: ^0.12.0
|
||||
version: 0.12.0(typescript@5.9.3)(zod@3.25.76)
|
||||
@ -204,14 +210,14 @@ importers:
|
||||
specifier: ^6.0.0
|
||||
version: 6.0.0
|
||||
shiki:
|
||||
specifier: 3.15.0
|
||||
version: 3.15.0
|
||||
specifier: 3.23.0
|
||||
version: 3.23.0
|
||||
sonner:
|
||||
specifier: ^2.0.7
|
||||
version: 2.0.7(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
|
||||
streamdown:
|
||||
specifier: 1.4.0
|
||||
version: 1.4.0(@types/react@19.2.13)(react@19.2.4)
|
||||
specifier: 2.5.0
|
||||
version: 2.5.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
|
||||
tailwind-merge:
|
||||
specifier: ^3.4.0
|
||||
version: 3.4.0
|
||||
@ -738,105 +744,89 @@ packages:
|
||||
resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-libvips-linux-arm@1.2.4':
|
||||
resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-libvips-linux-ppc64@1.2.4':
|
||||
resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-libvips-linux-riscv64@1.2.4':
|
||||
resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-libvips-linux-s390x@1.2.4':
|
||||
resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-libvips-linux-x64@1.2.4':
|
||||
resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-libvips-linuxmusl-arm64@1.2.4':
|
||||
resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@img/sharp-libvips-linuxmusl-x64@1.2.4':
|
||||
resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@img/sharp-linux-arm64@0.34.5':
|
||||
resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-linux-arm@0.34.5':
|
||||
resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-linux-ppc64@0.34.5':
|
||||
resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-linux-riscv64@0.34.5':
|
||||
resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-linux-s390x@0.34.5':
|
||||
resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-linux-x64@0.34.5':
|
||||
resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-linuxmusl-arm64@0.34.5':
|
||||
resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@img/sharp-linuxmusl-x64@0.34.5':
|
||||
resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@img/sharp-wasm32@0.34.5':
|
||||
resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==}
|
||||
@ -996,42 +986,36 @@ packages:
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@napi-rs/simple-git-linux-arm64-musl@0.1.22':
|
||||
resolution: {integrity: sha512-MOs7fPyJiU/wqOpKzAOmOpxJ/TZfP4JwmvPad/cXTOWYwwyppMlXFRms3i98EU3HOazI/wMU2Ksfda3+TBluWA==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@napi-rs/simple-git-linux-ppc64-gnu@0.1.22':
|
||||
resolution: {integrity: sha512-L59dR30VBShRUIZ5/cQHU25upNgKS0AMQ7537J6LCIUEFwwXrKORZKJ8ceR+s3Sr/4jempWVvMdjEpFDE4HYww==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@napi-rs/simple-git-linux-s390x-gnu@0.1.22':
|
||||
resolution: {integrity: sha512-4FHkPlCSIZUGC6HiADffbe6NVoTBMd65pIwcd40IDbtFKOgFMBA+pWRqKiQ21FERGH16Zed7XHJJoY3jpOqtmQ==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@napi-rs/simple-git-linux-x64-gnu@0.1.22':
|
||||
resolution: {integrity: sha512-Ei1tM5Ho/dwknF3pOzqkNW9Iv8oFzRxE8uOhrITcdlpxRxVrBVptUF6/0WPdvd7R9747D/q61QG/AVyWsWLFKw==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@napi-rs/simple-git-linux-x64-musl@0.1.22':
|
||||
resolution: {integrity: sha512-zRYxg7it0p3rLyEJYoCoL2PQJNgArVLyNavHW03TFUAYkYi5bxQ/UFNVpgxMaXohr5yu7qCBqeo9j4DWeysalg==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@napi-rs/simple-git-win32-arm64-msvc@0.1.22':
|
||||
resolution: {integrity: sha512-XGFR1fj+Y9cWACcovV2Ey/R2xQOZKs8t+7KHPerYdJ4PtjVzGznI4c2EBHXtdOIYvkw7tL5rZ7FN1HJKdD5Quw==}
|
||||
@ -1087,28 +1071,24 @@ packages:
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@next/swc-linux-arm64-musl@16.2.6':
|
||||
resolution: {integrity: sha512-URUTu1+dMkxJsPFgm+OeEvq9wf5sujw0EvgYy80TDGHTSLTnIHeqb0Eu8A3sC95IRgjejQL+kC4mw+4yPxiAXA==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@next/swc-linux-x64-gnu@16.2.6':
|
||||
resolution: {integrity: sha512-DOj182mPV8G3UkrayLoREM5YEYI+Dk5wv7Ox9xl1fFibAELEsFD0lDPfHIeILlutMMfdyhlzYPELG3peuKaurw==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@next/swc-linux-x64-musl@16.2.6':
|
||||
resolution: {integrity: sha512-HKQ5SP/V/ub73UvF7n/zeJlxk2kLmtL7Wzrg4WfmkjmNos5onJ2tKu7yZOPdL18A6Svfn3max29ym+ry7NkK4g==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@next/swc-win32-arm64-msvc@16.2.6':
|
||||
resolution: {integrity: sha512-LZXpTlPyS5v7HhSmnvsLGP3iIYgYOBnc8r8ArlT55sGHV89bR2HlDdBjWQ+PY6SJMmk8TuVGFuxalnP3k/0Dwg==}
|
||||
@ -1736,28 +1716,24 @@ packages:
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@resvg/resvg-js-linux-arm64-musl@2.6.2':
|
||||
resolution: {integrity: sha512-3h3dLPWNgSsD4lQBJPb4f+kvdOSJHa5PjTYVsWHxLUzH4IFTJUAnmuWpw4KqyQ3NA5QCyhw4TWgxk3jRkQxEKg==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@resvg/resvg-js-linux-x64-gnu@2.6.2':
|
||||
resolution: {integrity: sha512-IVUe+ckIerA7xMZ50duAZzwf1U7khQe2E0QpUxu5MBJNao5RqC0zwV/Zm965vw6D3gGFUl7j4m+oJjubBVoftw==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@resvg/resvg-js-linux-x64-musl@2.6.2':
|
||||
resolution: {integrity: sha512-UOf83vqTzoYQO9SZ0fPl2ZIFtNIz/Rr/y+7X8XRX1ZnBYsQ/tTb+cj9TE+KHOdmlTFBxhYzVkP2lRByCzqi4jQ==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@resvg/resvg-js-win32-arm64-msvc@2.6.2':
|
||||
resolution: {integrity: sha512-7C/RSgCa+7vqZ7qAbItfiaAWhyRSoD4l4BQAbVDqRRsRgY+S+hgS3in0Rxr7IorKUpGE69X48q6/nOAuTJQxeQ==}
|
||||
@ -1819,79 +1795,66 @@ packages:
|
||||
resolution: {integrity: sha512-n1GJHPOvpIfhi3TmrCeh6S6URt9BFCt0KQE3qvexyGCTAKpR4Lg+eWvNZEqu7epxwus/8ElT3hacYEucm49SZg==}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-arm-musleabihf@4.62.2':
|
||||
resolution: {integrity: sha512-JqgflS8wEB+UXV/vS1RpRbifGBeN4D5lz8D8oOFbFZw4vedvdOgCFAjfBmIMdW3yL10XpQQ0Ambepw6MXrhOnA==}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-linux-arm64-gnu@4.62.2':
|
||||
resolution: {integrity: sha512-wnFJkogWvN4jm/hQRF2UBaeUmk20j5+DmHvoyWii2b8HJDyvz1MF2OU/6ynXt2KR63rbZLWkFpoytpdc/yBuSA==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-arm64-musl@4.62.2':
|
||||
resolution: {integrity: sha512-HVu2bp0zhvJ8xHEV9+UUs7S90VadmBSY3LcIMvozbPo4AuMGDWlz3ymHLHZPX4hR67TKTt8Qp5PJ5RBg/i+RMQ==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-linux-loong64-gnu@4.62.2':
|
||||
resolution: {integrity: sha512-mQqqAV8QaoSgr9I2fKDLY2BAVvmKjWoGiu/cSYQonsLvtqwEn1E4QYfnCOcp5zoEqNhsDYin1s6jx/VJmrxlZg==}
|
||||
cpu: [loong64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-loong64-musl@4.62.2':
|
||||
resolution: {integrity: sha512-IxKLoxCQ2IWi6bT2akyDUBGsOImDKB+sPp4EsTmwFQ/fMwpCKm8uLSSgP/Kx/QYUgKis6SEZ5/Nlhup0DIA0PQ==}
|
||||
cpu: [loong64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-linux-ppc64-gnu@4.62.2':
|
||||
resolution: {integrity: sha512-Mk5ha2RQSgyFfmYYLkBpPnUk8D8FriBxesO1u9O75X0mHgXL1UQcH5Itl2lurWL2tj0RxV9b9tJgipac0hRY9A==}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-ppc64-musl@4.62.2':
|
||||
resolution: {integrity: sha512-CjvEnqJL/0/TQ3TXX3OPIJ/kmBellrWd4heXUmHeJlTnmwjKpSJzoehLaL6Xk0ZnMHBu9dZuFADNOrtjF4v+2w==}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-linux-riscv64-gnu@4.62.2':
|
||||
resolution: {integrity: sha512-1SiZbzwdkaDURsew/tSOrooKiYy7EQGT6m8ufavAi9NEyQb/6VuIxFXAL1fqa4iZe3g4NbNk4P7J32z2tw5Mgg==}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-riscv64-musl@4.62.2':
|
||||
resolution: {integrity: sha512-nQts12zJ3NQRoE6uYljOH89v7szzLDvG2JD/vsX+vGXU8w/At1GowTZ5/7qeFQ8m7L55rpR8Okugnuo5bgjy2Q==}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-linux-s390x-gnu@4.62.2':
|
||||
resolution: {integrity: sha512-E9/ll019jhPIJgpzfZoIkBGhcz+kKNgVWYRY0zr9srBdPPFVpvOKW8VaJKUbeK+eZXyQF9ltME+Kk6affeaPgg==}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-x64-gnu@4.62.2':
|
||||
resolution: {integrity: sha512-5BqxR/pshjey51iliyzTD5Xi3EN0aLmQ2lZ3lvefVV9c82BvrLo2/6OT55iifpWBufs6kdwWbuOKS841DrmK9A==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-x64-musl@4.62.2':
|
||||
resolution: {integrity: sha512-uNN83XxQrRAh/w0/pmAfibcwyb6YWt4gP+dpnQKPVJshAloQ785ii8CT8ZCIxkGg9opVsvAlGhFitSm6D1Jjpg==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-openbsd-x64@4.62.2':
|
||||
resolution: {integrity: sha512-srjEIxSH3LRnJN6THczDHWQplqEMFiAJrTab0msUryh9kwNpkICf3Ea6q6MN/2cZwRFUNx5w+h6Hpi4QuHS6Zg==}
|
||||
@ -1955,25 +1918,21 @@ packages:
|
||||
resolution: {integrity: sha512-pSI+npPQE/uDtiboqvcOIRJbEV2+B+H1xffmko/gw50la92oTUW60kVULFwsb6L0+GVCzIcwX3yq60GtYIn+Ug==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rspack/binding-linux-arm64-musl@2.0.8':
|
||||
resolution: {integrity: sha512-igjJ43yxWQ72GZqjDDZSSHax9/Vg+6rLMmOvFglTJUkQpB4Tyvu/YjW+WRjYj2xRw6blOjLxUSJWASvuSqqlvg==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rspack/binding-linux-x64-gnu@2.0.8':
|
||||
resolution: {integrity: sha512-zrkoEOnqj1hOEBO5T2I/2Ts2HSJsYFh1qXwMpK4dMJFGGNWDfNeUa6/LF5uq3VINF3JUl7RL47AgrucoSZJXPA==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rspack/binding-linux-x64-musl@2.0.8':
|
||||
resolution: {integrity: sha512-6CtDaGZjNDvJd9TBp7a9zABbrPORO21W96+3ZcGBn0YNUPUk4ARxIxrTTpeJ/1F41QDM8AYIkGDdqEYMqTYBsA==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rspack/binding-wasm32-wasi@2.0.8':
|
||||
resolution: {integrity: sha512-Yf4SiqTUroT5Ju+te0YAY2xxKOb35tECsO21v7hYyGa705wrgoAK/MmF7enOvs9GR1iZIqgiLD/wxsIxl8GjJw==}
|
||||
@ -2049,15 +2008,27 @@ packages:
|
||||
'@shikijs/engine-javascript@3.15.0':
|
||||
resolution: {integrity: sha512-ZedbOFpopibdLmvTz2sJPJgns8Xvyabe2QbmqMTz07kt1pTzfEvKZc5IqPVO/XFiEbbNyaOpjPBkkr1vlwS+qg==}
|
||||
|
||||
'@shikijs/engine-javascript@3.23.0':
|
||||
resolution: {integrity: sha512-aHt9eiGFobmWR5uqJUViySI1bHMqrAgamWE1TYSUoftkAeCCAiGawPMwM+VCadylQtF4V3VNOZ5LmfItH5f3yA==}
|
||||
|
||||
'@shikijs/engine-oniguruma@3.15.0':
|
||||
resolution: {integrity: sha512-HnqFsV11skAHvOArMZdLBZZApRSYS4LSztk2K3016Y9VCyZISnlYUYsL2hzlS7tPqKHvNqmI5JSUJZprXloMvA==}
|
||||
|
||||
'@shikijs/engine-oniguruma@3.23.0':
|
||||
resolution: {integrity: sha512-1nWINwKXxKKLqPibT5f4pAFLej9oZzQTsby8942OTlsJzOBZ0MWKiwzMsd+jhzu8YPCHAswGnnN1YtQfirL35g==}
|
||||
|
||||
'@shikijs/langs@3.15.0':
|
||||
resolution: {integrity: sha512-WpRvEFvkVvO65uKYW4Rzxs+IG0gToyM8SARQMtGGsH4GDMNZrr60qdggXrFOsdfOVssG/QQGEl3FnJ3EZ+8w8A==}
|
||||
|
||||
'@shikijs/langs@3.23.0':
|
||||
resolution: {integrity: sha512-2Ep4W3Re5aB1/62RSYQInK9mM3HsLeB91cHqznAJMuylqjzNVAVCMnNWRHFtcNHXsoNRayP9z1qj4Sq3nMqYXg==}
|
||||
|
||||
'@shikijs/themes@3.15.0':
|
||||
resolution: {integrity: sha512-8ow2zWb1IDvCKjYb0KiLNrK4offFdkfNVPXb1OZykpLCzRU6j+efkY+Y7VQjNlNFXonSw+4AOdGYtmqykDbRiQ==}
|
||||
|
||||
'@shikijs/themes@3.23.0':
|
||||
resolution: {integrity: sha512-5qySYa1ZgAT18HR/ypENL9cUSGOeI2x+4IvYJu4JgVJdizn6kG4ia5Q1jDEOi7gTbN4RbuYtmHh0W3eccOrjMA==}
|
||||
|
||||
'@shikijs/twoslash@3.23.0':
|
||||
resolution: {integrity: sha512-pNaLJWMA3LU7PhT8tm9OQBZ1epy0jmdgeJzntBtr1EVXLbHxGzTj3mnf9vOdcl84l96qnlJXkJ/NGXZYBpXl5g==}
|
||||
peerDependencies:
|
||||
@ -2084,6 +2055,16 @@ packages:
|
||||
'@standard-schema/spec@1.1.0':
|
||||
resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==}
|
||||
|
||||
'@streamdown/code@1.1.1':
|
||||
resolution: {integrity: sha512-i7HTNuDgZWb+VdrNVOam9gQhIc5MSSDXKWXgbUrn/4vSRaSMM+Rtl10MQj4wLWPNpF7p80waJsAqFP8HZfb0Jg==}
|
||||
peerDependencies:
|
||||
react: ^18.0.0 || ^19.0.0
|
||||
|
||||
'@streamdown/mermaid@1.0.2':
|
||||
resolution: {integrity: sha512-Fr/4sBWnAeSnxM3PcrV/+DiZe5oPMq9gOkUIAH7ZauJeuwrZ/DVzD4g0zlav6AH0axh2m/sOfrfLtY5aLT7niw==}
|
||||
peerDependencies:
|
||||
react: ^18.0.0 || ^19.0.0
|
||||
|
||||
'@swc/helpers@0.5.15':
|
||||
resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==}
|
||||
|
||||
@ -2159,28 +2140,24 @@ packages:
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@tailwindcss/oxide-linux-arm64-musl@4.1.18':
|
||||
resolution: {integrity: sha512-1px92582HkPQlaaCkdRcio71p8bc8i/ap5807tPRDK/uw953cauQBT8c5tVGkOwrHMfc2Yh6UuxaH4vtTjGvHg==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@tailwindcss/oxide-linux-x64-gnu@4.1.18':
|
||||
resolution: {integrity: sha512-v3gyT0ivkfBLoZGF9LyHmts0Isc8jHZyVcbzio6Wpzifg/+5ZJpDiRiUhDLkcr7f/r38SWNe7ucxmGW3j3Kb/g==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@tailwindcss/oxide-linux-x64-musl@4.1.18':
|
||||
resolution: {integrity: sha512-bhJ2y2OQNlcRwwgOAGMY0xTFStt4/wyU6pvI6LSuZpRgKQwxTec0/3Scu91O8ir7qCR3AuepQKLU/kX99FouqQ==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@tailwindcss/oxide-wasm32-wasi@4.1.18':
|
||||
resolution: {integrity: sha512-LffYTvPjODiP6PT16oNeUQJzNVyJl1cjIebq/rWWBF+3eDst5JGEFSc5cWxyRCJ0Mxl+KyIkqRxk1XPEs9x8TA==}
|
||||
@ -2584,49 +2561,41 @@ packages:
|
||||
resolution: {integrity: sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@unrs/resolver-binding-linux-arm64-musl@1.11.1':
|
||||
resolution: {integrity: sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@unrs/resolver-binding-linux-ppc64-gnu@1.11.1':
|
||||
resolution: {integrity: sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@unrs/resolver-binding-linux-riscv64-gnu@1.11.1':
|
||||
resolution: {integrity: sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@unrs/resolver-binding-linux-riscv64-musl@1.11.1':
|
||||
resolution: {integrity: sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@unrs/resolver-binding-linux-s390x-gnu@1.11.1':
|
||||
resolution: {integrity: sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@unrs/resolver-binding-linux-x64-gnu@1.11.1':
|
||||
resolution: {integrity: sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@unrs/resolver-binding-linux-x64-musl@1.11.1':
|
||||
resolution: {integrity: sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@unrs/resolver-binding-wasm32-wasi@1.11.1':
|
||||
resolution: {integrity: sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==}
|
||||
@ -3772,6 +3741,9 @@ packages:
|
||||
hast-util-raw@9.1.0:
|
||||
resolution: {integrity: sha512-Y8/SBAHkZGoNkpzqqfCldijcuUKh7/su31kEBp67cFY09Wy0mTRgtsLYsiIxMJxlu0f6AA5SUTbDR8K0rxnbUw==}
|
||||
|
||||
hast-util-sanitize@5.0.2:
|
||||
resolution: {integrity: sha512-3yTWghByc50aGS7JlGhk61SPenfE/p1oaFeNwkOOyrscaOkMGrcW9+Cy/QAIOBpZxP1yqDIzFMR0+Np0i0+usg==}
|
||||
|
||||
hast-util-to-estree@3.1.3:
|
||||
resolution: {integrity: sha512-48+B/rJWAp0jamNbAAf9M7Uf//UVqAoMmgXhBdxTDJLGKY+LRnZ99qcG+Qjl5HfMpYNzS5v4EAwVEF34LeAj7w==}
|
||||
|
||||
@ -4165,28 +4137,24 @@ packages:
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
lightningcss-linux-arm64-musl@1.30.2:
|
||||
resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
lightningcss-linux-x64-gnu@1.30.2:
|
||||
resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
lightningcss-linux-x64-musl@1.30.2:
|
||||
resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
lightningcss-win32-arm64-msvc@1.30.2:
|
||||
resolution: {integrity: sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==}
|
||||
@ -4231,11 +4199,6 @@ packages:
|
||||
resolution: {integrity: sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==}
|
||||
engines: {node: 20 || >=22}
|
||||
|
||||
lucide-react@0.542.0:
|
||||
resolution: {integrity: sha512-w3hD8/SQB7+lzU2r4VdFyzzOzKnUjTZIF/MQJGSSvni7Llewni4vuViRppfRAa2guOsY5k4jZyxw/i9DQHv+dw==}
|
||||
peerDependencies:
|
||||
react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
|
||||
lucide-react@0.562.0:
|
||||
resolution: {integrity: sha512-82hOAu7y0dbVuFfmO4bYF1XEwYk/mEbM5E+b1jgci/udUBEE/R7LF5Ip0CCEmXe8AybRM8L+04eP+LGZeDvkiw==}
|
||||
peerDependencies:
|
||||
@ -4256,6 +4219,11 @@ packages:
|
||||
engines: {node: '>= 20'}
|
||||
hasBin: true
|
||||
|
||||
marked@17.0.6:
|
||||
resolution: {integrity: sha512-gB0gkNafnonOw0obSTEGZTT86IuhILt2Wfx0mWH/1Au83kybTayroZ/V6nS25mN7u8ASy+5fMhgB3XPNrOZdmA==}
|
||||
engines: {node: '>= 20'}
|
||||
hasBin: true
|
||||
|
||||
marky@1.3.0:
|
||||
resolution: {integrity: sha512-ocnPZQLNpvbedwTy9kNrQEsknEfgvcLMvOtz3sFeWApDq1MXH1TqkCIx58xlpESsfwQOnuBO9beyQuNGzVvuhQ==}
|
||||
|
||||
@ -4942,12 +4910,6 @@ packages:
|
||||
react-is@16.13.1:
|
||||
resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}
|
||||
|
||||
react-markdown@10.1.0:
|
||||
resolution: {integrity: sha512-qKxVopLT/TyA6BX3Ue5NwabOsAzm0Q7kAPwq6L+wWDwisYs7R8vZ0nRXqq6rkueboxpkjvLGU9fWifiX/ZZFxQ==}
|
||||
peerDependencies:
|
||||
'@types/react': '>=18'
|
||||
react: '>=18'
|
||||
|
||||
react-medium-image-zoom@5.4.1:
|
||||
resolution: {integrity: sha512-DD2iZYaCfAwiQGR8AN62r/cDJYoXhezlYJc5HY4TzBUGuGge43CptG0f7m0PEIM72aN6GfpjohvY1yYdtCJB7g==}
|
||||
peerDependencies:
|
||||
@ -5036,8 +4998,8 @@ packages:
|
||||
resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
rehype-harden@1.1.7:
|
||||
resolution: {integrity: sha512-j5DY0YSK2YavvNGV+qBHma15J9m0WZmRe8posT5AtKDS6TNWtMVTo6RiqF8SidfcASYz8f3k2J/1RWmq5zTXUw==}
|
||||
rehype-harden@1.1.8:
|
||||
resolution: {integrity: sha512-Qn7vR1xrf6fZCrkm9TDWi/AB4ylrHy+jqsNm1EHOAmbARYA6gsnVJBq/sdBh6kmT4NEZxH5vgIjrscefJAOXcw==}
|
||||
|
||||
rehype-katex@7.0.1:
|
||||
resolution: {integrity: sha512-OiM2wrZ/wuhKkigASodFoo8wimG3H12LWQaH8qSPVJn9apWKFSH3YOCtbKpBorTVw/eI7cuT21XBbvwEswbIOA==}
|
||||
@ -5057,6 +5019,9 @@ packages:
|
||||
rehype-recma@1.0.0:
|
||||
resolution: {integrity: sha512-lqA4rGUf1JmacCNWWZx0Wv1dHqMwxzsDWYMTowuplHF3xH0N/MmrZ/G3BDZnzAkRmxDadujCjaKM2hqYdCBOGw==}
|
||||
|
||||
rehype-sanitize@6.0.0:
|
||||
resolution: {integrity: sha512-CsnhKNsyI8Tub6L4sm5ZFsme4puGfc6pYylvXo1AeqaGbjOYyzNv3qZPwvs0oMJ39eryyeOdmxwUIo94IpEhqg==}
|
||||
|
||||
rehype-slug@6.0.0:
|
||||
resolution: {integrity: sha512-lWyvf/jwu+oS5+hL5eClVd3hNdmwM1kAC0BUvEGD19pajQMIzcNUd/k9GsfQ+FfECvX+JE+e9/btsKH0EjJT6A==}
|
||||
|
||||
@ -5088,6 +5053,9 @@ packages:
|
||||
remark-stringify@11.0.0:
|
||||
resolution: {integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==}
|
||||
|
||||
remend@1.3.0:
|
||||
resolution: {integrity: sha512-iIhggPkhW3hFImKtB10w0dz4EZbs28mV/dmbcYVonWEJ6UGHHpP+bFZnTh6GNWJONg5m+U56JrL+8IxZRdgWjw==}
|
||||
|
||||
resolve-from@4.0.0:
|
||||
resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
|
||||
engines: {node: '>=4'}
|
||||
@ -5212,6 +5180,9 @@ packages:
|
||||
shiki@3.15.0:
|
||||
resolution: {integrity: sha512-kLdkY6iV3dYbtPwS9KXU7mjfmDm25f5m0IPNFnaXO7TBPcvbUOY72PYXSuSqDzwp+vlH/d7MXpHlKO/x+QoLXw==}
|
||||
|
||||
shiki@3.23.0:
|
||||
resolution: {integrity: sha512-55Dj73uq9ZXL5zyeRPzHQsK7Nbyt6Y10k5s7OjuFZGMhpp4r/rsLBH0o/0fstIzX1Lep9VxefWljK/SKCzygIA==}
|
||||
|
||||
side-channel-list@1.0.0:
|
||||
resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==}
|
||||
engines: {node: '>= 0.4'}
|
||||
@ -5279,10 +5250,11 @@ packages:
|
||||
resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
streamdown@1.4.0:
|
||||
resolution: {integrity: sha512-ylhDSQ4HpK5/nAH9v7OgIIdGJxlJB2HoYrYkJNGrO8lMpnWuKUcrz/A8xAMwA6eILA27469vIavcOTjmxctrKg==}
|
||||
streamdown@2.5.0:
|
||||
resolution: {integrity: sha512-/tTnURfIOxZK/pqJAxsfCvETG/XCJHoWnk3jq9xLcuz6CSpnjjuxSRBTTL4PKGhxiZQf0lqPxGhImdpwcZ2XwA==}
|
||||
peerDependencies:
|
||||
react: ^18.0.0 || ^19.0.0
|
||||
react-dom: ^18.0.0 || ^19.0.0
|
||||
|
||||
string.prototype.codepointat@0.2.1:
|
||||
resolution: {integrity: sha512-2cBVCj6I4IOvEnjgO/hWqXjqBGsY+zwPmHl12Srk9IXSZ56Jwwmy+66XO5Iut/oQVR7t5ihYdLB0GMa4alEUcg==}
|
||||
@ -6622,7 +6594,7 @@ snapshots:
|
||||
|
||||
'@mdx-js/mdx@3.1.1':
|
||||
dependencies:
|
||||
'@types/estree': 1.0.8
|
||||
'@types/estree': 1.0.9
|
||||
'@types/estree-jsx': 1.0.5
|
||||
'@types/hast': 3.0.4
|
||||
'@types/mdx': 2.0.13
|
||||
@ -7602,19 +7574,38 @@ snapshots:
|
||||
'@shikijs/vscode-textmate': 10.0.2
|
||||
oniguruma-to-es: 4.3.4
|
||||
|
||||
'@shikijs/engine-javascript@3.23.0':
|
||||
dependencies:
|
||||
'@shikijs/types': 3.23.0
|
||||
'@shikijs/vscode-textmate': 10.0.2
|
||||
oniguruma-to-es: 4.3.4
|
||||
|
||||
'@shikijs/engine-oniguruma@3.15.0':
|
||||
dependencies:
|
||||
'@shikijs/types': 3.15.0
|
||||
'@shikijs/vscode-textmate': 10.0.2
|
||||
|
||||
'@shikijs/engine-oniguruma@3.23.0':
|
||||
dependencies:
|
||||
'@shikijs/types': 3.23.0
|
||||
'@shikijs/vscode-textmate': 10.0.2
|
||||
|
||||
'@shikijs/langs@3.15.0':
|
||||
dependencies:
|
||||
'@shikijs/types': 3.15.0
|
||||
|
||||
'@shikijs/langs@3.23.0':
|
||||
dependencies:
|
||||
'@shikijs/types': 3.23.0
|
||||
|
||||
'@shikijs/themes@3.15.0':
|
||||
dependencies:
|
||||
'@shikijs/types': 3.15.0
|
||||
|
||||
'@shikijs/themes@3.23.0':
|
||||
dependencies:
|
||||
'@shikijs/types': 3.23.0
|
||||
|
||||
'@shikijs/twoslash@3.23.0(typescript@5.9.3)':
|
||||
dependencies:
|
||||
'@shikijs/core': 3.23.0
|
||||
@ -7645,6 +7636,16 @@ snapshots:
|
||||
|
||||
'@standard-schema/spec@1.1.0': {}
|
||||
|
||||
'@streamdown/code@1.1.1(react@19.2.4)':
|
||||
dependencies:
|
||||
react: 19.2.4
|
||||
shiki: 3.23.0
|
||||
|
||||
'@streamdown/mermaid@1.0.2(react@19.2.4)':
|
||||
dependencies:
|
||||
mermaid: 11.12.2
|
||||
react: 19.2.4
|
||||
|
||||
'@swc/helpers@0.5.15':
|
||||
dependencies:
|
||||
tslib: 2.8.1
|
||||
@ -7920,7 +7921,7 @@ snapshots:
|
||||
|
||||
'@types/estree-jsx@1.0.5':
|
||||
dependencies:
|
||||
'@types/estree': 1.0.8
|
||||
'@types/estree': 1.0.9
|
||||
|
||||
'@types/estree@1.0.8': {}
|
||||
|
||||
@ -9301,7 +9302,7 @@ snapshots:
|
||||
|
||||
estree-util-attach-comments@3.0.0:
|
||||
dependencies:
|
||||
'@types/estree': 1.0.8
|
||||
'@types/estree': 1.0.9
|
||||
|
||||
estree-util-build-jsx@3.0.1:
|
||||
dependencies:
|
||||
@ -9314,7 +9315,7 @@ snapshots:
|
||||
|
||||
estree-util-scope@1.0.0:
|
||||
dependencies:
|
||||
'@types/estree': 1.0.8
|
||||
'@types/estree': 1.0.9
|
||||
devlop: 1.1.0
|
||||
|
||||
estree-util-to-js@2.0.0:
|
||||
@ -9325,7 +9326,7 @@ snapshots:
|
||||
|
||||
estree-util-value-to-estree@3.5.0:
|
||||
dependencies:
|
||||
'@types/estree': 1.0.8
|
||||
'@types/estree': 1.0.9
|
||||
|
||||
estree-util-visit@2.0.0:
|
||||
dependencies:
|
||||
@ -9336,7 +9337,7 @@ snapshots:
|
||||
|
||||
estree-walker@3.0.3:
|
||||
dependencies:
|
||||
'@types/estree': 1.0.8
|
||||
'@types/estree': 1.0.9
|
||||
|
||||
esutils@2.0.3: {}
|
||||
|
||||
@ -9643,9 +9644,15 @@ snapshots:
|
||||
web-namespaces: 2.0.1
|
||||
zwitch: 2.0.4
|
||||
|
||||
hast-util-sanitize@5.0.2:
|
||||
dependencies:
|
||||
'@types/hast': 3.0.4
|
||||
'@ungap/structured-clone': 1.3.0
|
||||
unist-util-position: 5.0.0
|
||||
|
||||
hast-util-to-estree@3.1.3:
|
||||
dependencies:
|
||||
'@types/estree': 1.0.8
|
||||
'@types/estree': 1.0.9
|
||||
'@types/estree-jsx': 1.0.5
|
||||
'@types/hast': 3.0.4
|
||||
comma-separated-tokens: 2.0.3
|
||||
@ -9680,7 +9687,7 @@ snapshots:
|
||||
|
||||
hast-util-to-jsx-runtime@2.3.6:
|
||||
dependencies:
|
||||
'@types/estree': 1.0.8
|
||||
'@types/estree': 1.0.9
|
||||
'@types/hast': 3.0.4
|
||||
'@types/unist': 3.0.3
|
||||
comma-separated-tokens: 2.0.3
|
||||
@ -10102,10 +10109,6 @@ snapshots:
|
||||
|
||||
lru-cache@11.5.2: {}
|
||||
|
||||
lucide-react@0.542.0(react@19.2.4):
|
||||
dependencies:
|
||||
react: 19.2.4
|
||||
|
||||
lucide-react@0.562.0(react@19.2.4):
|
||||
dependencies:
|
||||
react: 19.2.4
|
||||
@ -10120,6 +10123,8 @@ snapshots:
|
||||
|
||||
marked@16.4.2: {}
|
||||
|
||||
marked@17.0.6: {}
|
||||
|
||||
marky@1.3.0: {}
|
||||
|
||||
math-intrinsics@1.1.0: {}
|
||||
@ -10442,7 +10447,7 @@ snapshots:
|
||||
|
||||
micromark-extension-mdx-expression@3.0.1:
|
||||
dependencies:
|
||||
'@types/estree': 1.0.8
|
||||
'@types/estree': 1.0.9
|
||||
devlop: 1.1.0
|
||||
micromark-factory-mdx-expression: 2.0.3
|
||||
micromark-factory-space: 2.0.1
|
||||
@ -10453,7 +10458,7 @@ snapshots:
|
||||
|
||||
micromark-extension-mdx-jsx@3.0.2:
|
||||
dependencies:
|
||||
'@types/estree': 1.0.8
|
||||
'@types/estree': 1.0.9
|
||||
devlop: 1.1.0
|
||||
estree-util-is-identifier-name: 3.0.0
|
||||
micromark-factory-mdx-expression: 2.0.3
|
||||
@ -10470,7 +10475,7 @@ snapshots:
|
||||
|
||||
micromark-extension-mdxjs-esm@3.0.0:
|
||||
dependencies:
|
||||
'@types/estree': 1.0.8
|
||||
'@types/estree': 1.0.9
|
||||
devlop: 1.1.0
|
||||
micromark-core-commonmark: 2.0.3
|
||||
micromark-util-character: 2.1.1
|
||||
@ -10506,7 +10511,7 @@ snapshots:
|
||||
|
||||
micromark-factory-mdx-expression@2.0.3:
|
||||
dependencies:
|
||||
'@types/estree': 1.0.8
|
||||
'@types/estree': 1.0.9
|
||||
devlop: 1.1.0
|
||||
micromark-factory-space: 2.0.1
|
||||
micromark-util-character: 2.1.1
|
||||
@ -10570,7 +10575,7 @@ snapshots:
|
||||
|
||||
micromark-util-events-to-acorn@2.0.3:
|
||||
dependencies:
|
||||
'@types/estree': 1.0.8
|
||||
'@types/estree': 1.0.9
|
||||
'@types/unist': 3.0.3
|
||||
devlop: 1.1.0
|
||||
estree-util-visit: 2.0.0
|
||||
@ -11155,24 +11160,6 @@ snapshots:
|
||||
|
||||
react-is@16.13.1: {}
|
||||
|
||||
react-markdown@10.1.0(@types/react@19.2.13)(react@19.2.4):
|
||||
dependencies:
|
||||
'@types/hast': 3.0.4
|
||||
'@types/mdast': 4.0.4
|
||||
'@types/react': 19.2.13
|
||||
devlop: 1.1.0
|
||||
hast-util-to-jsx-runtime: 2.3.6
|
||||
html-url-attributes: 3.0.1
|
||||
mdast-util-to-hast: 13.2.1
|
||||
react: 19.2.4
|
||||
remark-parse: 11.0.0
|
||||
remark-rehype: 11.1.2
|
||||
unified: 11.0.5
|
||||
unist-util-visit: 5.1.0
|
||||
vfile: 6.0.3
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
react-medium-image-zoom@5.4.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4):
|
||||
dependencies:
|
||||
react: 19.2.4
|
||||
@ -11220,7 +11207,7 @@ snapshots:
|
||||
|
||||
recma-build-jsx@1.0.0:
|
||||
dependencies:
|
||||
'@types/estree': 1.0.8
|
||||
'@types/estree': 1.0.9
|
||||
estree-util-build-jsx: 3.0.1
|
||||
vfile: 6.0.3
|
||||
|
||||
@ -11235,14 +11222,14 @@ snapshots:
|
||||
|
||||
recma-parse@1.0.0:
|
||||
dependencies:
|
||||
'@types/estree': 1.0.8
|
||||
'@types/estree': 1.0.9
|
||||
esast-util-from-js: 2.0.1
|
||||
unified: 11.0.5
|
||||
vfile: 6.0.3
|
||||
|
||||
recma-stringify@1.0.0:
|
||||
dependencies:
|
||||
'@types/estree': 1.0.8
|
||||
'@types/estree': 1.0.9
|
||||
estree-util-to-js: 2.0.0
|
||||
unified: 11.0.5
|
||||
vfile: 6.0.3
|
||||
@ -11277,7 +11264,7 @@ snapshots:
|
||||
gopd: 1.2.0
|
||||
set-function-name: 2.0.2
|
||||
|
||||
rehype-harden@1.1.7:
|
||||
rehype-harden@1.1.8:
|
||||
dependencies:
|
||||
unist-util-visit: 5.1.0
|
||||
|
||||
@ -11315,12 +11302,17 @@ snapshots:
|
||||
|
||||
rehype-recma@1.0.0:
|
||||
dependencies:
|
||||
'@types/estree': 1.0.8
|
||||
'@types/estree': 1.0.9
|
||||
'@types/hast': 3.0.4
|
||||
hast-util-to-estree: 3.1.3
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
rehype-sanitize@6.0.0:
|
||||
dependencies:
|
||||
'@types/hast': 3.0.4
|
||||
hast-util-sanitize: 5.0.2
|
||||
|
||||
rehype-slug@6.0.0:
|
||||
dependencies:
|
||||
'@types/hast': 3.0.4
|
||||
@ -11402,6 +11394,8 @@ snapshots:
|
||||
mdast-util-to-markdown: 2.1.2
|
||||
unified: 11.0.5
|
||||
|
||||
remend@1.3.0: {}
|
||||
|
||||
resolve-from@4.0.0: {}
|
||||
|
||||
resolve-pkg-maps@1.0.0: {}
|
||||
@ -11617,6 +11611,17 @@ snapshots:
|
||||
'@shikijs/vscode-textmate': 10.0.2
|
||||
'@types/hast': 3.0.4
|
||||
|
||||
shiki@3.23.0:
|
||||
dependencies:
|
||||
'@shikijs/core': 3.23.0
|
||||
'@shikijs/engine-javascript': 3.23.0
|
||||
'@shikijs/engine-oniguruma': 3.23.0
|
||||
'@shikijs/langs': 3.23.0
|
||||
'@shikijs/themes': 3.23.0
|
||||
'@shikijs/types': 3.23.0
|
||||
'@shikijs/vscode-textmate': 10.0.2
|
||||
'@types/hast': 3.0.4
|
||||
|
||||
side-channel-list@1.0.0:
|
||||
dependencies:
|
||||
es-errors: 1.3.0
|
||||
@ -11688,24 +11693,27 @@ snapshots:
|
||||
es-errors: 1.3.0
|
||||
internal-slot: 1.1.0
|
||||
|
||||
streamdown@1.4.0(@types/react@19.2.13)(react@19.2.4):
|
||||
streamdown@2.5.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4):
|
||||
dependencies:
|
||||
clsx: 2.1.1
|
||||
katex: 0.16.28
|
||||
lucide-react: 0.542.0(react@19.2.4)
|
||||
marked: 16.4.2
|
||||
hast-util-to-jsx-runtime: 2.3.6
|
||||
html-url-attributes: 3.0.1
|
||||
marked: 17.0.6
|
||||
mermaid: 11.12.2
|
||||
react: 19.2.4
|
||||
react-markdown: 10.1.0(@types/react@19.2.13)(react@19.2.4)
|
||||
rehype-harden: 1.1.7
|
||||
rehype-katex: 7.0.1
|
||||
react-dom: 19.2.4(react@19.2.4)
|
||||
rehype-harden: 1.1.8
|
||||
rehype-raw: 7.0.0
|
||||
rehype-sanitize: 6.0.0
|
||||
remark-gfm: 4.0.1
|
||||
remark-math: 6.0.0
|
||||
shiki: 3.15.0
|
||||
remark-parse: 11.0.0
|
||||
remark-rehype: 11.1.2
|
||||
remend: 1.3.0
|
||||
tailwind-merge: 3.4.0
|
||||
unified: 11.0.5
|
||||
unist-util-visit: 5.1.0
|
||||
unist-util-visit-parents: 6.0.2
|
||||
transitivePeerDependencies:
|
||||
- '@types/react'
|
||||
- supports-color
|
||||
|
||||
string.prototype.codepointat@0.2.1: {}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import "katex/dist/katex.min.css";
|
||||
import "streamdown/styles.css";
|
||||
import "@/styles/globals.css";
|
||||
|
||||
import { type Metadata } from "next";
|
||||
|
||||
@ -44,7 +44,10 @@ import { writeTextToClipboard } from "@/core/clipboard";
|
||||
import { useI18n } from "@/core/i18n/hooks";
|
||||
import { findToolCallResult } from "@/core/messages/utils";
|
||||
import { installSkill, SkillRequestError } from "@/core/skills/api";
|
||||
import { SafeStreamdown } from "@/core/streamdown/components";
|
||||
import {
|
||||
SafeStreamdown,
|
||||
toStreamdownComponents,
|
||||
} from "@/core/streamdown/components";
|
||||
import {
|
||||
canBrowserPreviewFile,
|
||||
checkCodeFile,
|
||||
@ -521,7 +524,7 @@ export function ArtifactFilePreview({
|
||||
<SafeStreamdown
|
||||
className="min-w-0"
|
||||
{...artifactMarkdownPlugins}
|
||||
components={{ a: ArtifactLink }}
|
||||
components={toStreamdownComponents({ a: ArtifactLink })}
|
||||
>
|
||||
{content ?? ""}
|
||||
</SafeStreamdown>
|
||||
|
||||
@ -17,8 +17,13 @@ import { type ClipboardSafeStreamdownProps } from "@/components/ai-elements/stre
|
||||
import {
|
||||
preprocessStreamdownMarkdown,
|
||||
streamdownPluginsWithoutRawHtml,
|
||||
streamdownWordAnimation,
|
||||
} from "@/core/streamdown";
|
||||
import { SafeMessageResponse } from "@/core/streamdown/components";
|
||||
import {
|
||||
SafeMessageResponse,
|
||||
type StreamdownComponentOverrides,
|
||||
toStreamdownComponents,
|
||||
} from "@/core/streamdown/components";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
import { createMarkdownLinkComponent } from "./markdown-link";
|
||||
@ -29,7 +34,7 @@ export type MarkdownContentProps = {
|
||||
rehypePlugins?: ClipboardSafeStreamdownProps["rehypePlugins"];
|
||||
className?: string;
|
||||
remarkPlugins?: ClipboardSafeStreamdownProps["remarkPlugins"];
|
||||
components?: ClipboardSafeStreamdownProps["components"];
|
||||
components?: StreamdownComponentOverrides;
|
||||
};
|
||||
|
||||
type StreamingCodeProps = ComponentProps<"code"> & {
|
||||
@ -260,8 +265,10 @@ export function MarkdownContent({
|
||||
className={className}
|
||||
remarkPlugins={remarkPlugins}
|
||||
rehypePlugins={effectiveRehypePlugins}
|
||||
components={components}
|
||||
parseIncompleteMarkdown={isStreamingRender}
|
||||
components={toStreamdownComponents(components)}
|
||||
parseIncompleteMarkdown={isLoading}
|
||||
animated={streamdownWordAnimation}
|
||||
isAnimating={isLoading}
|
||||
>
|
||||
{normalizedContent}
|
||||
</SafeMessageResponse>
|
||||
|
||||
@ -35,7 +35,6 @@ import {
|
||||
extractReasoningContentFromMessage,
|
||||
findToolCallResult,
|
||||
} from "@/core/messages/utils";
|
||||
import { useRehypeSplitWordsIntoSpans } from "@/core/rehype";
|
||||
import { extractTitleFromMarkdown } from "@/core/utils/markdown";
|
||||
import { env } from "@/env";
|
||||
import { cn } from "@/lib/utils";
|
||||
@ -121,7 +120,6 @@ function MessageGroupComponent({
|
||||
return filteredSteps[filteredSteps.length - 1];
|
||||
}
|
||||
}, [lastToolCallStep, steps]);
|
||||
const rehypePlugins = useRehypeSplitWordsIntoSpans(isLoading);
|
||||
const firstEligibleDebugSummaryStepIndexByMessageId = useMemo(() => {
|
||||
const firstIndices = new Map<string, number>();
|
||||
|
||||
@ -242,13 +240,7 @@ function MessageGroupComponent({
|
||||
<ChainOfThoughtStep
|
||||
key={step.id}
|
||||
icon={MessageSquareTextIcon}
|
||||
label={
|
||||
<MarkdownContent
|
||||
content={step.content}
|
||||
isLoading={isLoading}
|
||||
rehypePlugins={rehypePlugins}
|
||||
/>
|
||||
}
|
||||
label={<MarkdownContent content={step.content} isLoading={isLoading} />}
|
||||
></ChainOfThoughtStep>
|
||||
);
|
||||
|
||||
@ -269,7 +261,6 @@ function MessageGroupComponent({
|
||||
<MarkdownContent
|
||||
content={step.reasoning ?? ""}
|
||||
isLoading={isLoading}
|
||||
rehypePlugins={rehypePlugins}
|
||||
/>
|
||||
}
|
||||
></ChainOfThoughtStep>,
|
||||
@ -390,7 +381,6 @@ function MessageGroupComponent({
|
||||
<MarkdownContent
|
||||
content={lastReasoningStep.reasoning ?? ""}
|
||||
isLoading={isLoading}
|
||||
rehypePlugins={rehypePlugins}
|
||||
/>
|
||||
}
|
||||
></ChainOfThoughtStep>
|
||||
|
||||
@ -45,7 +45,6 @@ import {
|
||||
stripUploadedFilesTag,
|
||||
type FileInMessage,
|
||||
} from "@/core/messages/utils";
|
||||
import { useRehypeSplitWordsIntoSpans } from "@/core/rehype";
|
||||
import { readReferenceMessageContexts } from "@/core/sidecar";
|
||||
import {
|
||||
parseSlashSkillReference,
|
||||
@ -295,7 +294,6 @@ function MessageContent_({
|
||||
runId?: string;
|
||||
turnStartTime?: number | null;
|
||||
}) {
|
||||
const rehypePlugins = useRehypeSplitWordsIntoSpans(isLoading);
|
||||
const isHuman = message.type === "human";
|
||||
const rawTurnDuration = message.additional_kwargs?.turn_duration as
|
||||
| number
|
||||
@ -478,7 +476,6 @@ function MessageContent_({
|
||||
<MarkdownContent
|
||||
content={contentToDisplay}
|
||||
isLoading={isLoading}
|
||||
rehypePlugins={rehypePlugins}
|
||||
className="my-3"
|
||||
components={components}
|
||||
/>
|
||||
|
||||
@ -58,7 +58,6 @@ import {
|
||||
isHiddenFromUIMessage,
|
||||
type MessageGroup as ThreadMessageGroup,
|
||||
} from "@/core/messages/utils";
|
||||
import { useRehypeSplitWordsIntoSpans } from "@/core/rehype";
|
||||
import {
|
||||
buildMessageSidecarContext,
|
||||
type SidecarContext,
|
||||
@ -434,7 +433,6 @@ export function MessageList({
|
||||
.slice(lastHumanIndex)
|
||||
.some((g) => g.type === "assistant");
|
||||
}, [groupedMessages]);
|
||||
const rehypePlugins = useRehypeSplitWordsIntoSpans(thread.isLoading);
|
||||
const updateSubtask = useUpdateSubtask();
|
||||
const lastGroupIndex = groupedMessages.length - 1;
|
||||
const turnUsageMessagesByGroupIndex =
|
||||
@ -1036,7 +1034,6 @@ export function MessageList({
|
||||
<MarkdownContent
|
||||
content={extractContentFromMessage(message)}
|
||||
isLoading={thread.isLoading}
|
||||
rehypePlugins={rehypePlugins}
|
||||
/>
|
||||
{renderTokenUsage({
|
||||
messages: group.messages,
|
||||
@ -1060,7 +1057,6 @@ export function MessageList({
|
||||
<MarkdownContent
|
||||
content={extractContentFromMessage(group.messages[0])}
|
||||
isLoading={thread.isLoading}
|
||||
rehypePlugins={rehypePlugins}
|
||||
className="mb-4"
|
||||
/>
|
||||
)}
|
||||
|
||||
@ -20,9 +20,14 @@ import { ShineBorder } from "@/components/ui/shine-border";
|
||||
import { useI18n } from "@/core/i18n/hooks";
|
||||
import { hasToolCalls } from "@/core/messages/utils";
|
||||
import { useModels } from "@/core/models/hooks";
|
||||
import { useRehypeSplitWordsIntoSpans } from "@/core/rehype";
|
||||
import { streamdownPluginsWithWordAnimation } from "@/core/streamdown";
|
||||
import { SafeStreamdown } from "@/core/streamdown/components";
|
||||
import {
|
||||
streamdownPluginsWithoutRawHtml,
|
||||
streamdownWordAnimation,
|
||||
} from "@/core/streamdown";
|
||||
import {
|
||||
SafeStreamdown,
|
||||
toStreamdownComponents,
|
||||
} from "@/core/streamdown/components";
|
||||
import { fetchSubtaskSteps } from "@/core/tasks/api";
|
||||
import { useSubtask, useUpdateSubtask } from "@/core/tasks/context";
|
||||
import {
|
||||
@ -53,7 +58,6 @@ export function SubtaskCard({
|
||||
}) {
|
||||
const { t } = useI18n();
|
||||
const [collapsed, setCollapsed] = useState(true);
|
||||
const rehypePlugins = useRehypeSplitWordsIntoSpans(isLoading);
|
||||
const task = useSubtask(taskId)!;
|
||||
const { models, tokenUsageEnabled } = useModels();
|
||||
const updateSubtask = useUpdateSubtask();
|
||||
@ -195,8 +199,10 @@ export function SubtaskCard({
|
||||
<ChainOfThoughtStep
|
||||
label={
|
||||
<SafeStreamdown
|
||||
{...streamdownPluginsWithWordAnimation}
|
||||
components={{ a: CitationLink }}
|
||||
{...streamdownPluginsWithoutRawHtml}
|
||||
animated={streamdownWordAnimation}
|
||||
components={toStreamdownComponents({ a: CitationLink })}
|
||||
isAnimating={isLoading}
|
||||
>
|
||||
{task.prompt}
|
||||
</SafeStreamdown>
|
||||
@ -221,11 +227,7 @@ export function SubtaskCard({
|
||||
(step.tool_name ?? t.subtasks[task.status])
|
||||
) : (
|
||||
<div className="text-muted-foreground line-clamp-3 text-sm">
|
||||
<MarkdownContent
|
||||
content={step.text}
|
||||
isLoading={false}
|
||||
rehypePlugins={rehypePlugins}
|
||||
/>
|
||||
<MarkdownContent content={step.text} isLoading={false} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@ -242,11 +244,7 @@ export function SubtaskCard({
|
||||
<ChainOfThoughtStep
|
||||
label={
|
||||
task.result ? (
|
||||
<MarkdownContent
|
||||
content={task.result}
|
||||
isLoading={false}
|
||||
rehypePlugins={rehypePlugins}
|
||||
/>
|
||||
<MarkdownContent content={task.result} isLoading={false} />
|
||||
) : null
|
||||
}
|
||||
></ChainOfThoughtStep>
|
||||
|
||||
@ -1,56 +0,0 @@
|
||||
import type { Element, Root, ElementContent } from "hast";
|
||||
import { useMemo } from "react";
|
||||
import { visit } from "unist-util-visit";
|
||||
import type { BuildVisitor } from "unist-util-visit";
|
||||
|
||||
const CJK_TEXT_RE =
|
||||
/[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Hangul}]/u;
|
||||
|
||||
export function rehypeSplitWordsIntoSpans() {
|
||||
return (tree: Root) => {
|
||||
visit(tree, "element", ((node: Element) => {
|
||||
if (
|
||||
["p", "h1", "h2", "h3", "h4", "h5", "h6", "li", "strong"].includes(
|
||||
node.tagName,
|
||||
) &&
|
||||
node.children
|
||||
) {
|
||||
const newChildren: Array<ElementContent> = [];
|
||||
node.children.forEach((child) => {
|
||||
if (child.type === "text") {
|
||||
if (CJK_TEXT_RE.test(child.value)) {
|
||||
newChildren.push(child);
|
||||
return;
|
||||
}
|
||||
const segmenter = new Intl.Segmenter("zh", { granularity: "word" });
|
||||
const segments = segmenter.segment(child.value);
|
||||
const words = Array.from(segments)
|
||||
.map((segment) => segment.segment)
|
||||
.filter(Boolean);
|
||||
words.forEach((word: string) => {
|
||||
newChildren.push({
|
||||
type: "element",
|
||||
tagName: "span",
|
||||
properties: {
|
||||
className: "animate-fade-in",
|
||||
},
|
||||
children: [{ type: "text", value: word }],
|
||||
});
|
||||
});
|
||||
} else {
|
||||
newChildren.push(child);
|
||||
}
|
||||
});
|
||||
node.children = newChildren;
|
||||
}
|
||||
}) as BuildVisitor<Root, "element">);
|
||||
};
|
||||
}
|
||||
|
||||
export function useRehypeSplitWordsIntoSpans(enabled = true) {
|
||||
const rehypePlugins = useMemo(
|
||||
() => (enabled ? [rehypeSplitWordsIntoSpans] : []),
|
||||
[enabled],
|
||||
);
|
||||
return rehypePlugins;
|
||||
}
|
||||
@ -1,9 +1,8 @@
|
||||
"use client";
|
||||
|
||||
import {
|
||||
MessageResponse,
|
||||
type MessageResponseProps,
|
||||
} from "@/components/ai-elements/message";
|
||||
import type { ComponentType, JSX } from "react";
|
||||
import type { Components, ExtraProps } from "streamdown";
|
||||
|
||||
import {
|
||||
ReasoningContent,
|
||||
type ReasoningContentProps,
|
||||
@ -12,30 +11,73 @@ import {
|
||||
ClipboardSafeStreamdown,
|
||||
type ClipboardSafeStreamdownProps,
|
||||
} from "@/components/ai-elements/streamdown";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
import { streamdownRenderingPlugins } from "./plugins";
|
||||
import {
|
||||
useSafeStreamdownChildren,
|
||||
useSafeStreamdownMarkdown,
|
||||
} from "./safe-children";
|
||||
|
||||
export type StreamdownComponentOverrides = {
|
||||
[Key in keyof JSX.IntrinsicElements]?:
|
||||
| ComponentType<JSX.IntrinsicElements[Key] & ExtraProps>
|
||||
| keyof JSX.IntrinsicElements;
|
||||
} & {
|
||||
inlineCode?: ComponentType<JSX.IntrinsicElements["code"] & ExtraProps>;
|
||||
};
|
||||
|
||||
/**
|
||||
* Adapts normal intrinsic-element overrides to Streamdown's component map.
|
||||
*
|
||||
* Streamdown 2.5's public `Components` type combines those overrides with a
|
||||
* catch-all index signature whose generic props reject correctly typed React
|
||||
* components. The runtime contract still accepts this standard component map,
|
||||
* so keep the compatibility cast at this boundary instead of every caller.
|
||||
*/
|
||||
export function toStreamdownComponents(
|
||||
components: StreamdownComponentOverrides,
|
||||
): Components {
|
||||
return components as unknown as Components;
|
||||
}
|
||||
|
||||
export function SafeStreamdown({
|
||||
children,
|
||||
plugins = streamdownRenderingPlugins,
|
||||
...props
|
||||
}: ClipboardSafeStreamdownProps) {
|
||||
const safeChildren = useSafeStreamdownChildren(children);
|
||||
|
||||
return (
|
||||
<ClipboardSafeStreamdown {...props}>{safeChildren}</ClipboardSafeStreamdown>
|
||||
<ClipboardSafeStreamdown plugins={plugins} {...props}>
|
||||
{safeChildren}
|
||||
</ClipboardSafeStreamdown>
|
||||
);
|
||||
}
|
||||
|
||||
export function SafeMessageResponse({
|
||||
children,
|
||||
className,
|
||||
plugins = streamdownRenderingPlugins,
|
||||
...props
|
||||
}: MessageResponseProps) {
|
||||
}: ClipboardSafeStreamdownProps) {
|
||||
const safeChildren = useSafeStreamdownChildren(children);
|
||||
|
||||
return <MessageResponse {...props}>{safeChildren}</MessageResponse>;
|
||||
// Keep this wrapper outside the registry-generated MessageResponse component.
|
||||
// That component memoizes only by children, while Streamdown's animation
|
||||
// lifecycle also needs isAnimating/animated prop changes to render.
|
||||
return (
|
||||
<ClipboardSafeStreamdown
|
||||
className={cn(
|
||||
"size-full [&>*:first-child]:mt-0 [&>*:last-child]:mb-0",
|
||||
className,
|
||||
)}
|
||||
plugins={plugins}
|
||||
{...props}
|
||||
>
|
||||
{safeChildren}
|
||||
</ClipboardSafeStreamdown>
|
||||
);
|
||||
}
|
||||
|
||||
export function SafeReasoningContent({
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
import { code } from "@streamdown/code";
|
||||
import { mermaid } from "@streamdown/mermaid";
|
||||
import rehypeKatex from "rehype-katex";
|
||||
import rehypeRaw from "rehype-raw";
|
||||
import remarkGfm from "remark-gfm";
|
||||
import remarkMath from "remark-math";
|
||||
import type { StreamdownProps } from "streamdown";
|
||||
|
||||
import { rehypeSplitWordsIntoSpans } from "../rehype";
|
||||
|
||||
const katexOptions = {
|
||||
output: "html",
|
||||
throwOnError: false,
|
||||
@ -17,7 +17,13 @@ const sharedRemarkPlugins = [
|
||||
[remarkMath, { singleDollarTextMath: true }],
|
||||
] as StreamdownProps["remarkPlugins"];
|
||||
|
||||
export const streamdownRenderingPlugins = {
|
||||
code,
|
||||
mermaid,
|
||||
} satisfies NonNullable<StreamdownProps["plugins"]>;
|
||||
|
||||
export const streamdownPlugins = {
|
||||
plugins: streamdownRenderingPlugins,
|
||||
remarkPlugins: sharedRemarkPlugins,
|
||||
rehypePlugins: [
|
||||
rehypeRaw,
|
||||
@ -25,15 +31,14 @@ export const streamdownPlugins = {
|
||||
] as StreamdownProps["rehypePlugins"],
|
||||
};
|
||||
|
||||
export const streamdownPluginsWithWordAnimation = {
|
||||
remarkPlugins: sharedRemarkPlugins,
|
||||
rehypePlugins: [
|
||||
[rehypeKatex, katexOptions],
|
||||
rehypeSplitWordsIntoSpans,
|
||||
] as StreamdownProps["rehypePlugins"],
|
||||
};
|
||||
export const streamdownWordAnimation = {
|
||||
animation: "fadeIn",
|
||||
duration: 200,
|
||||
sep: "word",
|
||||
} as const satisfies Exclude<StreamdownProps["animated"], boolean | undefined>;
|
||||
|
||||
export const streamdownPluginsWithoutRawHtml = {
|
||||
plugins: streamdownPlugins.plugins,
|
||||
remarkPlugins: streamdownPlugins.remarkPlugins,
|
||||
rehypePlugins: streamdownPlugins.rehypePlugins?.filter(
|
||||
(p) => p !== rehypeRaw,
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
@import "tailwindcss";
|
||||
@import "tw-animate-css";
|
||||
|
||||
@source "../node_modules/streamdown/dist/index.js";
|
||||
@source "../../node_modules/streamdown/dist/index.js";
|
||||
@source "../../node_modules/@streamdown/code/dist/*.js";
|
||||
@source "../../node_modules/@streamdown/mermaid/dist/*.js";
|
||||
|
||||
/* Heading */
|
||||
@source inline("text-{xs,sm,base,lg,xl,2xl,3xl,4xl,5xl,6xl}");
|
||||
|
||||
@ -8,6 +8,10 @@ import {
|
||||
|
||||
const mermaidContent = `Here is a relationship diagram.
|
||||
|
||||
\`\`\`typescript
|
||||
const answer: number = 42;
|
||||
\`\`\`
|
||||
|
||||
\`\`\`mermaid
|
||||
flowchart TD
|
||||
A[Lin<br/>protagonist]
|
||||
@ -87,4 +91,22 @@ test("historical run messages preview labelled dotted Mermaid arrows", async ({
|
||||
timeout: 15_000,
|
||||
});
|
||||
await expect(page.getByText("Mermaid Error:")).toHaveCount(0);
|
||||
const highlightedTokens = page.locator(
|
||||
'[data-streamdown="code-block-body"] code > span > span',
|
||||
);
|
||||
await expect
|
||||
.poll(() => highlightedTokens.count(), { timeout: 15_000 })
|
||||
.toBeGreaterThan(1);
|
||||
const tokenStyles = await highlightedTokens.evaluateAll((tokens) =>
|
||||
tokens.map((token) => ({
|
||||
color: getComputedStyle(token).color,
|
||||
style: token.getAttribute("style"),
|
||||
})),
|
||||
);
|
||||
expect(new Set(tokenStyles.map(({ style }) => style)).size).toBeGreaterThan(
|
||||
1,
|
||||
);
|
||||
expect(new Set(tokenStyles.map(({ color }) => color)).size).toBeGreaterThan(
|
||||
1,
|
||||
);
|
||||
});
|
||||
|
||||
@ -43,9 +43,9 @@ describe("MarkdownContent streaming code blocks", () => {
|
||||
expect(html).not.toContain('data-streaming-inline-code="true"');
|
||||
});
|
||||
|
||||
it("restores Streamdown highlighting after streaming finishes", () => {
|
||||
it("restores Streamdown code rendering after streaming finishes", () => {
|
||||
const html = renderMarkdown(
|
||||
["```html", '<main class="report">Hello</main>', "```"].join("\n"),
|
||||
["```typescript", "const answer: number = 42;", "```"].join("\n"),
|
||||
false,
|
||||
);
|
||||
|
||||
@ -91,6 +91,23 @@ describe("MarkdownContent streaming code blocks", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("MarkdownContent streaming animation", () => {
|
||||
it("uses Streamdown animation only for newly streamed words", () => {
|
||||
const html = renderMarkdown("Hello streaming world", true);
|
||||
|
||||
expect(html).toContain("data-sd-animate");
|
||||
expect(html).toContain("--sd-animation:sd-fadeIn");
|
||||
expect(html).toContain("--sd-duration:200ms");
|
||||
expect(html).not.toContain("animate-fade-in");
|
||||
});
|
||||
|
||||
it("does not animate completed markdown", () => {
|
||||
const html = renderMarkdown("Hello completed world", false);
|
||||
|
||||
expect(html).not.toContain("data-sd-animate");
|
||||
});
|
||||
});
|
||||
|
||||
describe("MarkdownContent strikethrough", () => {
|
||||
it("preserves single tildes in temperature ranges", () => {
|
||||
const html = renderMarkdown("周六23~30℃;周日22~30℃", false);
|
||||
|
||||
@ -4,13 +4,20 @@ import { renderToStaticMarkup } from "react-dom/server";
|
||||
|
||||
import { artifactMarkdownPlugins } from "@/components/workspace/artifacts/markdown-preview-plugins";
|
||||
import { ArtifactLink } from "@/components/workspace/citations/artifact-link";
|
||||
import { SafeStreamdown, streamdownPlugins } from "@/core/streamdown";
|
||||
import {
|
||||
SafeStreamdown,
|
||||
streamdownPlugins,
|
||||
toStreamdownComponents,
|
||||
} from "@/core/streamdown";
|
||||
|
||||
function renderArtifactMarkdown(content: string) {
|
||||
return renderToStaticMarkup(
|
||||
createElement(
|
||||
SafeStreamdown,
|
||||
{ ...artifactMarkdownPlugins, components: { a: ArtifactLink } },
|
||||
{
|
||||
...artifactMarkdownPlugins,
|
||||
components: toStreamdownComponents({ a: ArtifactLink }),
|
||||
},
|
||||
content,
|
||||
),
|
||||
);
|
||||
|
||||
@ -1,26 +1,65 @@
|
||||
import { expect, test } from "@rstest/core";
|
||||
import { code, type HighlightResult } from "@streamdown/code";
|
||||
import { mermaid } from "@streamdown/mermaid";
|
||||
import rehypeRaw from "rehype-raw";
|
||||
import remarkGfm from "remark-gfm";
|
||||
|
||||
import {
|
||||
reasoningPlugins,
|
||||
streamdownPlugins,
|
||||
streamdownPluginsWithWordAnimation,
|
||||
streamdownRenderingPlugins,
|
||||
streamdownWordAnimation,
|
||||
} from "@/core/streamdown/plugins";
|
||||
|
||||
test("shared streamdown configs disable single-tilde strikethrough", () => {
|
||||
const expectedGfmPlugin = [remarkGfm, { singleTilde: false }];
|
||||
|
||||
expect(streamdownPlugins.remarkPlugins).toContainEqual(expectedGfmPlugin);
|
||||
expect(streamdownPluginsWithWordAnimation.remarkPlugins).toContainEqual(
|
||||
expectedGfmPlugin,
|
||||
);
|
||||
});
|
||||
|
||||
test("streaming word animation uses Streamdown's stable incremental animation", () => {
|
||||
expect(streamdownWordAnimation).toEqual({
|
||||
animation: "fadeIn",
|
||||
duration: 200,
|
||||
sep: "word",
|
||||
});
|
||||
});
|
||||
|
||||
test("streamdownPlugins includes rehypeRaw", () => {
|
||||
expect(streamdownPlugins.rehypePlugins).toContain(rehypeRaw);
|
||||
});
|
||||
|
||||
test("shared streamdown configs register code highlighting and Mermaid", () => {
|
||||
expect(streamdownRenderingPlugins).toEqual({ code, mermaid });
|
||||
expect(streamdownPlugins.plugins).toBe(streamdownRenderingPlugins);
|
||||
expect(reasoningPlugins.plugins).toBe(streamdownRenderingPlugins);
|
||||
});
|
||||
|
||||
test("the shared code plugin produces highlighted Shiki tokens", async () => {
|
||||
const source = "const answer: number = 42;";
|
||||
const highlighted = await new Promise<HighlightResult>((resolve) => {
|
||||
const cached = code.highlight(
|
||||
{
|
||||
code: source,
|
||||
language: "typescript",
|
||||
themes: code.getThemes(),
|
||||
},
|
||||
resolve,
|
||||
);
|
||||
if (cached) {
|
||||
resolve(cached);
|
||||
}
|
||||
});
|
||||
|
||||
expect(
|
||||
highlighted.tokens
|
||||
.flat()
|
||||
.some((token) =>
|
||||
/^#[0-9A-Fa-f]{6}$/.test(String(token.htmlStyle?.color ?? "")),
|
||||
),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
test("reasoningPlugins does not include rehypeRaw", () => {
|
||||
const flat = reasoningPlugins.rehypePlugins?.flat();
|
||||
expect(flat).not.toContain(rehypeRaw);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user