From 14739ba2e6d34c68fe479f53afc413be3cac9e50 Mon Sep 17 00:00:00 2001 From: Quentin BEY Date: Thu, 16 Oct 2025 10:27:14 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B(llm)=20use=20Tex=20markers=20for?= =?UTF-8?q?=20formula=20rendering?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous implementation was expecting dollar signs for formulas, but mistral seems trained on \(...\) and \[...\] format. Let's hope it does not break anything. --- .../chat/conversations/test_conversation.py | 38 +++------ .../test_conversation_with_document_upload.py | 11 +-- .../test_conversation_with_history.py | 16 +--- src/backend/conversations/settings.py | 6 +- .../apps/conversations/next.config.js | 5 ++ src/frontend/apps/conversations/package.json | 1 + src/frontend/yarn.lock | 81 ++++++++++++++----- 7 files changed, 88 insertions(+), 70 deletions(-) diff --git a/src/backend/chat/tests/views/chat/conversations/test_conversation.py b/src/backend/chat/tests/views/chat/conversations/test_conversation.py index 44fd464..ce35580 100644 --- a/src/backend/chat/tests/views/chat/conversations/test_conversation.py +++ b/src/backend/chat/tests/views/chat/conversations/test_conversation.py @@ -34,6 +34,7 @@ def ai_settings(settings): settings.AI_BASE_URL = "https://www.external-ai-service.com/" settings.AI_API_KEY = "test-api-key" settings.AI_MODEL = "test-model" + settings.AI_AGENT_INSTRUCTIONS = "You are a helpful test assistant :)" return settings @@ -164,10 +165,7 @@ def test_post_conversation_data_protocol(api_client, mock_openai_stream, mock_uu "kind": "request", "parts": [ { - "content": "You are a helpful assistant. Escape formulas or any " - "math notation between `$$`, like `$$x^2 + y^2 = " - "z^2$$` or `$$C_l$$`. You can use Markdown to format " - "your answers. ", + "content": "You are a helpful test assistant :)", "dynamic_ref": None, "part_kind": "system-prompt", "timestamp": "2025-07-25T10:36:35.297675Z", @@ -288,10 +286,7 @@ def test_post_conversation_text_protocol(api_client, mock_openai_stream, mock_uu "kind": "request", "parts": [ { - "content": "You are a helpful assistant. Escape formulas or any " - "math notation between `$$`, like `$$x^2 + y^2 = " - "z^2$$` or `$$C_l$$`. You can use Markdown to format " - "your answers. ", + "content": "You are a helpful test assistant :)", "dynamic_ref": None, "part_kind": "system-prompt", "timestamp": "2025-07-25T10:36:35.297675Z", @@ -392,9 +387,7 @@ def test_post_conversation_with_image(api_client, mock_openai_stream_image, mock # Check the exact structure expected by the AI service assert body["messages"] == [ { - "content": "You are a helpful assistant. Escape formulas or any math " - "notation between `$$`, like `$$x^2 + y^2 = z^2$$` or `$$C_l$$`. " - "You can use Markdown to format your answers. ", + "content": "You are a helpful test assistant :)", "role": "system", }, {"content": "Today is Friday 25/07/2025.", "role": "system"}, @@ -484,10 +477,7 @@ def test_post_conversation_with_image(api_client, mock_openai_stream_image, mock "kind": "request", "parts": [ { - "content": "You are a helpful assistant. Escape formulas or any " - "math notation between `$$`, like `$$x^2 + y^2 = " - "z^2$$` or `$$C_l$$`. You can use Markdown to format " - "your answers. ", + "content": "You are a helpful test assistant :)", "dynamic_ref": None, "part_kind": "system-prompt", "timestamp": "2025-07-25T10:36:35.297675Z", @@ -595,9 +585,7 @@ def test_post_conversation_tool_call(api_client, mock_openai_stream_tool, mock_u assert body["messages"] == [ { - "content": "You are a helpful assistant. Escape formulas or any math " - "notation between `$$`, like `$$x^2 + y^2 = z^2$$` or `$$C_l$$`. " - "You can use Markdown to format your answers. ", + "content": "You are a helpful test assistant :)", "role": "system", }, {"content": "Today is Friday 25/07/2025.", "role": "system"}, @@ -660,10 +648,7 @@ def test_post_conversation_tool_call(api_client, mock_openai_stream_tool, mock_u "kind": "request", "parts": [ { - "content": "You are a helpful assistant. Escape formulas or any " - "math notation between `$$`, like `$$x^2 + y^2 = " - "z^2$$` or `$$C_l$$`. You can use Markdown to format " - "your answers. ", + "content": "You are a helpful test assistant :)", "dynamic_ref": None, "part_kind": "system-prompt", "timestamp": "2025-07-25T10:36:35.297675Z", @@ -804,9 +789,7 @@ def test_post_conversation_tool_call_fails( assert body["messages"] == [ { - "content": "You are a helpful assistant. Escape formulas or any math " - "notation between `$$`, like `$$x^2 + y^2 = z^2$$` or `$$C_l$$`. " - "You can use Markdown to format your answers. ", + "content": "You are a helpful test assistant :)", "role": "system", }, {"content": "Today is Friday 25/07/2025.", "role": "system"}, @@ -869,10 +852,7 @@ def test_post_conversation_tool_call_fails( "kind": "request", "parts": [ { - "content": "You are a helpful assistant. Escape formulas or any " - "math notation between `$$`, like `$$x^2 + y^2 = " - "z^2$$` or `$$C_l$$`. You can use Markdown to format " - "your answers. ", + "content": "You are a helpful test assistant :)", "dynamic_ref": None, "part_kind": "system-prompt", "timestamp": "2025-07-25T10:36:35.297675Z", diff --git a/src/backend/chat/tests/views/chat/conversations/test_conversation_with_document_upload.py b/src/backend/chat/tests/views/chat/conversations/test_conversation_with_document_upload.py index ce28210..a7c4cc6 100644 --- a/src/backend/chat/tests/views/chat/conversations/test_conversation_with_document_upload.py +++ b/src/backend/chat/tests/views/chat/conversations/test_conversation_with_document_upload.py @@ -45,6 +45,7 @@ def ai_settings(settings): settings.AI_BASE_URL = "https://www.external-ai-service.com/" settings.AI_API_KEY = "test-api-key" settings.AI_MODEL = "test-model" + settings.AI_AGENT_INSTRUCTIONS = "You are a helpful test assistant :)" # Enable Albert API for document search settings.RAG_DOCUMENT_SEARCH_BACKEND = ( @@ -343,10 +344,7 @@ def test_post_conversation_with_document_upload( # pylint: disable=too-many-arg "kind": "request", "parts": [ { - "content": "You are a helpful assistant. Escape formulas or any " - "math notation between `$$`, like `$$x^2 + y^2 = z^2$$` " - "or `$$C_l$$`. You can use Markdown to format your " - "answers. ", + "content": "You are a helpful test assistant :)", "dynamic_ref": None, "part_kind": "system-prompt", "timestamp": "2025-07-25T10:36:35.297675Z", @@ -662,10 +660,7 @@ def test_post_conversation_with_document_upload_summarize( # pylint: disable=to "kind": "request", "parts": [ { - "content": "You are a helpful assistant. Escape formulas or any " - "math notation between `$$`, like `$$x^2 + y^2 = z^2$$` " - "or `$$C_l$$`. You can use Markdown to format your " - "answers. ", + "content": "You are a helpful test assistant :)", "dynamic_ref": None, "part_kind": "system-prompt", "timestamp": "2025-07-25T10:36:35.297675Z", diff --git a/src/backend/chat/tests/views/chat/conversations/test_conversation_with_history.py b/src/backend/chat/tests/views/chat/conversations/test_conversation_with_history.py index 1804784..23ea90a 100644 --- a/src/backend/chat/tests/views/chat/conversations/test_conversation_with_history.py +++ b/src/backend/chat/tests/views/chat/conversations/test_conversation_with_history.py @@ -31,6 +31,7 @@ def ai_settings(settings): settings.AI_BASE_URL = "https://www.external-ai-service.com/" settings.AI_API_KEY = "test-api-key" settings.AI_MODEL = "test-model" + settings.AI_AGENT_INSTRUCTIONS = "You are a helpful test assistant :)" return settings @@ -121,10 +122,7 @@ def history_conversation_fixture(): "kind": "request", "parts": [ { - "content": "You are a helpful assistant. Escape formulas or any " - "math notation between `$$`, like `$$x^2 + y^2 = " - "z^2$$` or `$$C_l$$`. You can use Markdown to format " - "your answers. ", + "content": "You are a helpful test assistant :)", "dynamic_ref": None, "part_kind": "system-prompt", "timestamp": "2025-06-15T10:30:00.000000Z", @@ -807,10 +805,7 @@ def history_conversation_with_image_fixture(): "kind": "request", "parts": [ { - "content": "You are a helpful assistant. Escape formulas or any " - "math notation between `$$`, like `$$x^2 + y^2 = " - "z^2$$` or `$$C_l$$`. You can use Markdown to format " - "your answers. ", + "content": "You are a helpful test assistant :)", "dynamic_ref": None, "part_kind": "system-prompt", "timestamp": "2025-06-15T10:30:00.000000Z", @@ -988,10 +983,7 @@ def history_conversation_with_tool_fixture(): "kind": "request", "parts": [ { - "content": "You are a helpful assistant. Escape formulas or any " - "math notation between `$$`, like `$$x^2 + y^2 = " - "z^2$$` or `$$C_l$$`. You can use Markdown to format " - "your answers. ", + "content": "You are a helpful test assistant :)", "dynamic_ref": None, "part_kind": "system-prompt", "timestamp": "2025-06-15T10:30:00.000000Z", diff --git a/src/backend/conversations/settings.py b/src/backend/conversations/settings.py index 5187d01..2e676cf 100755 --- a/src/backend/conversations/settings.py +++ b/src/backend/conversations/settings.py @@ -502,9 +502,9 @@ class Base(BraveSettings, Configuration): AI_AGENT_INSTRUCTIONS = values.Value( ( "You are a helpful assistant. " - "Escape formulas or any math notation between `$$`, " - "like `$$x^2 + y^2 = z^2$$` or `$$C_l$$`. " - "You can use Markdown to format your answers. " + "Wrap formulas or any math notation between `\\(...\\)` and `\\[...\\]`, " + "like `\\(x^2 + y^2 = z^2\\)` for inline formula or `\\[C_l\\]` for display. " + "You must use Markdown to format your answers except when asked otherwise. " ), environ_name="AI_AGENT_INSTRUCTIONS", environ_prefix=None, diff --git a/src/frontend/apps/conversations/next.config.js b/src/frontend/apps/conversations/next.config.js index 51cb587..698a435 100644 --- a/src/frontend/apps/conversations/next.config.js +++ b/src/frontend/apps/conversations/next.config.js @@ -44,6 +44,11 @@ const nextConfig = { // Modify the file loader rule to ignore *.svg, since we have it handled now. fileLoaderRule.exclude = /\.svg$/i; + // Formula rendering in markdown, replace dollar-sign with \(...\) and \[...\] + // https://github.com/remarkjs/remark-math/issues/39#issuecomment-2636184992 + config.resolve.alias['micromark-extension-math'] = + 'micromark-extension-llm-math'; + return config; }, }; diff --git a/src/frontend/apps/conversations/package.json b/src/frontend/apps/conversations/package.json index 6ba0d03..1c2d102 100644 --- a/src/frontend/apps/conversations/package.json +++ b/src/frontend/apps/conversations/package.json @@ -37,6 +37,7 @@ "idb": "8.0.3", "lodash": "4.17.21", "luxon": "3.6.1", + "micromark-extension-llm-math": "3.1.1-20250610", "next": "15.3.3", "posthog-js": "1.249.3", "react": "*", diff --git a/src/frontend/yarn.lock b/src/frontend/yarn.lock index 258ac04..0756b62 100644 --- a/src/frontend/yarn.lock +++ b/src/frontend/yarn.lock @@ -5602,13 +5602,20 @@ dependencies: "@types/node" "*" -"@types/node@*", "@types/node@22.10.7", "@types/node@22.15.29": +"@types/node@*": version "22.15.29" resolved "https://registry.yarnpkg.com/@types/node/-/node-22.15.29.tgz#c75999124a8224a3f79dd8b6ccfb37d74098f678" integrity sha512-LNdjOkUDlU1RZb8e1kOIUpN1qQUlzGkEtbVNo53vbrwDg5om6oduhm4SiUaPW5ASTXhAiP0jInWG8Qx9fVlOeQ== dependencies: undici-types "~6.21.0" +"@types/node@22.10.7": + version "22.10.7" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.10.7.tgz#14a1ca33fd0ebdd9d63593ed8d3fbc882a6d28d7" + integrity sha512-V09KvXxFiutGp6B7XkpaDXlNadZxrzajcY50EuoLIpQ6WWYCSvf19lVIazzfIzQvhUN2HjX12spLojTnhuKlGg== + dependencies: + undici-types "~6.20.0" + "@types/parse-json@^4.0.0": version "4.0.2" resolved "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz" @@ -5642,7 +5649,7 @@ resolved "https://registry.npmjs.org/@types/raf/-/raf-3.4.3.tgz" integrity sha512-c4YAvMedbPZ5tEyxzQdMoOhhJ4RD3rngZIdwC2/qDN3d7JpEhB6fiBRKVY1lg5B7Wk+uPBjn5f39j1/2MY1oOw== -"@types/react-dom@*", "@types/react-dom@19.1.6": +"@types/react-dom@*": version "19.1.6" resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-19.1.6.tgz#4af629da0e9f9c0f506fc4d1caa610399c595d64" integrity sha512-4hOiT/dwO8Ko0gV1m/TJZYk3y0KBnY9vzDh7W+DH17b2HFSOGgdj33dhihPeuy3l0q23+4e+hoXHV6hCC4dCXw== @@ -5659,7 +5666,7 @@ resolved "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.12.tgz" integrity sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w== -"@types/react@*", "@types/react@19.1.6": +"@types/react@*": version "19.1.6" resolved "https://registry.yarnpkg.com/@types/react/-/react-19.1.6.tgz#dee39f3e1e9a7d693f156a5840570b6d57f325ea" integrity sha512-JeG0rEWak0N6Itr6QUx+X60uQmN+5t3j9r/OVDtWzFXKaj6kD1BwJzOksD0FF6iWxZlbE1kB0q9vtnU2ekqa1Q== @@ -5730,7 +5737,7 @@ dependencies: "@types/yargs-parser" "*" -"@typescript-eslint/eslint-plugin@*", "@typescript-eslint/eslint-plugin@8.33.1", "@typescript-eslint/eslint-plugin@^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0": +"@typescript-eslint/eslint-plugin@*", "@typescript-eslint/eslint-plugin@^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0": version "8.33.1" resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.33.1.tgz#532641b416ed2afd5be893cddb2a58e9cd1f7a3e" integrity sha512-TDCXj+YxLgtvxvFlAvpoRv9MAncDLBV2oT9Bd7YBGC/b/sEURoOYuIwLI99rjWOfY3QtDzO+mk0n4AmdFExW8A== @@ -5745,7 +5752,7 @@ natural-compare "^1.4.0" ts-api-utils "^2.1.0" -"@typescript-eslint/parser@*", "@typescript-eslint/parser@8.33.1", "@typescript-eslint/parser@^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0": +"@typescript-eslint/parser@*", "@typescript-eslint/parser@^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0": version "8.33.1" resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.33.1.tgz#ef9a5ee6aa37a6b4f46cc36d08a14f828238afe2" integrity sha512-qwxv6dq682yVvgKKp2qWwLgRbscDAYktPptK4JPojCwwi3R9cwrvIxS4lvBpzmcqzR4bdn54Z0IG1uHFskW4dA== @@ -7935,7 +7942,7 @@ eslint-visitor-keys@^4.2.0: resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz" integrity sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ== -eslint@*, eslint@8.57.0: +eslint@*: version "8.57.0" resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.57.0.tgz#c786a6fd0e0b68941aaf624596fb987089195668" integrity sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ== @@ -10090,7 +10097,7 @@ longest-streak@^3.0.0: resolved "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz" integrity sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g== -loose-envify@^1.0.0, loose-envify@^1.4.0: +loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0: version "1.4.0" resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz" integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== @@ -10533,6 +10540,19 @@ micromark-extension-gfm@^3.0.0: micromark-util-combine-extensions "^2.0.0" micromark-util-types "^2.0.0" +micromark-extension-llm-math@^3.1.1-20250610: + version "3.1.1-20250610" + resolved "https://registry.yarnpkg.com/micromark-extension-llm-math/-/micromark-extension-llm-math-3.1.1-20250610.tgz#35546a19c5a98e89cc7a5b259bc071e2d0e672e9" + integrity sha512-sI1JuyhP5v4ALRKOtOeh/hEfuf+xQwRXfX4/Rg55cwv1ySzQdRW/UoIKPtVbiXgnrI8oBh0BrFo2k9M3q1VJ9g== + dependencies: + "@types/katex" "^0.16.0" + devlop "^1.0.0" + katex "^0.16.0" + micromark-factory-space "^2.0.0" + micromark-util-character "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + micromark-extension-math@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/micromark-extension-math/-/micromark-extension-math-3.1.0.tgz#c42ee3b1dd5a9a03584e83dd8f08e3de510212c1" @@ -11772,12 +11792,20 @@ react-dnd@^14.0.3: fast-deep-equal "^3.1.3" hoist-non-react-statics "^3.3.2" -react-dom@18.3.1, react-dom@19.0.0, react-dom@19.1.0: - version "19.1.0" - resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-19.1.0.tgz#133558deca37fa1d682708df8904b25186793623" - integrity sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g== +react-dom@18.3.1: + version "18.3.1" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.3.1.tgz#c2265d79511b57d479b3dd3fdfa51536494c5cb4" + integrity sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw== dependencies: - scheduler "^0.26.0" + loose-envify "^1.1.0" + scheduler "^0.23.2" + +react-dom@19.0.0: + version "19.0.0" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-19.0.0.tgz#43446f1f01c65a4cd7f7588083e686a6726cfb57" + integrity sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ== + dependencies: + scheduler "^0.25.0" react-i18next@15.5.2: version "15.5.2" @@ -12008,11 +12036,16 @@ react-window@^1.8.11: "@babel/runtime" "^7.0.0" memoize-one ">=3.1.1 <6" -react@*, react@19.0.0, react@19.1.0: +react@*: version "19.1.0" resolved "https://registry.yarnpkg.com/react/-/react-19.1.0.tgz#926864b6c48da7627f004795d6cce50e90793b75" integrity sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg== +react@19.0.0: + version "19.0.0" + resolved "https://registry.yarnpkg.com/react/-/react-19.0.0.tgz#6e1969251b9f108870aa4bff37a0ce9ddfaaabdd" + integrity sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ== + readable-stream@^3.4.0: version "3.6.2" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" @@ -12451,10 +12484,17 @@ scheduler@0.25.0-rc-603e6108-20241029: resolved "https://registry.npmjs.org/scheduler/-/scheduler-0.25.0-rc-603e6108-20241029.tgz" integrity sha512-pFwF6H1XrSdYYNLfOcGlM28/j8CGLu8IvdrxqhjWULe2bPcKiKW4CV+OWqR/9fT52mywx65l7ysNkjLKBda7eA== -scheduler@^0.26.0: - version "0.26.0" - resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.26.0.tgz#4ce8a8c2a2095f13ea11bf9a445be50c555d6337" - integrity sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA== +scheduler@^0.23.2: + version "0.23.2" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.2.tgz#414ba64a3b282892e944cf2108ecc078d115cdc3" + integrity sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ== + dependencies: + loose-envify "^1.1.0" + +scheduler@^0.25.0: + version "0.25.0" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.25.0.tgz#336cd9768e8cceebf52d3c80e3dcf5de23e7e015" + integrity sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA== schema-utils@^4.3.0, schema-utils@^4.3.2: version "4.3.2" @@ -13454,7 +13494,7 @@ typed-array-length@^1.0.7: possible-typed-array-names "^1.0.0" reflect.getprototypeof "^1.0.6" -typescript@*, typescript@5.8.3, typescript@^5.0.4: +typescript@*, typescript@^5.0.4: version "5.8.3" resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.8.3.tgz#92f8a3e5e3cf497356f4178c34cd65a7f5e8440e" integrity sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ== @@ -13477,6 +13517,11 @@ underscore.string@~3.3.4: sprintf-js "^1.1.1" util-deprecate "^1.0.2" +undici-types@~6.20.0: + version "6.20.0" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.20.0.tgz#8171bf22c1f588d1554d55bf204bc624af388433" + integrity sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg== + undici-types@~6.21.0: version "6.21.0" resolved "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz"