From 57d630fa568de4c028eb15f7a62b2b1d275ebbe2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=B0=D1=81=D0=B8=D0=BB=D0=B8=D0=B9=20=D0=95=D0=BB?= =?UTF-8?q?=D0=B8=D1=81=D0=B5=D0=B5=D0=B2?= Date: Wed, 22 Apr 2026 17:02:50 +0600 Subject: [PATCH 1/7] feat: add parse tools content logic --- .../lib/components/ai-message/component.tsx | 6 +- .../chat/features/chat/src/lib/utils/index.ts | 1 + .../utils/parse-response-message-content.ts | 206 ++++++++++++++++ package-lock.json | 231 ++++++++---------- package.json | 1 + 5 files changed, 315 insertions(+), 130 deletions(-) create mode 100644 libs/mobile/chat/features/chat/src/lib/utils/parse-response-message-content.ts diff --git a/libs/mobile/chat/features/chat/src/lib/components/ai-message/component.tsx b/libs/mobile/chat/features/chat/src/lib/components/ai-message/component.tsx index a4e8540..27b1654 100644 --- a/libs/mobile/chat/features/chat/src/lib/components/ai-message/component.tsx +++ b/libs/mobile/chat/features/chat/src/lib/components/ai-message/component.tsx @@ -17,6 +17,7 @@ import { Message } from '@open-webui-react-native/shared/data-access/api'; import { FileType } from '@open-webui-react-native/shared/data-access/common'; import { getApiUrl } from '@open-webui-react-native/shared/utils/config'; import { formatDateTime } from '@open-webui-react-native/shared/utils/date'; +import { parseResponseMessageContent } from '../../utils'; import { ChatImagesGroup } from '../images'; import { SkeletonMessage } from '../skeleton-message'; @@ -71,9 +72,12 @@ export function ChatAiMessage({ const { handleImagePress, handleAllPhotosPress, selectedImageIndex, isPreviewVisible, handleCloseImagePress } = useImagePreview(); - const textWithCitations = prepareTextWithCitations(text, citations); + const { toolsData, messageContent } = parseResponseMessageContent(text); + const textWithCitations = prepareTextWithCitations(messageContent, citations); const hasFollowUps = Array.isArray(followUps) && followUps.length > 0; + console.log('toolsData', toolsData); + return ( diff --git a/libs/mobile/chat/features/chat/src/lib/utils/index.ts b/libs/mobile/chat/features/chat/src/lib/utils/index.ts index 62470b9..047452f 100644 --- a/libs/mobile/chat/features/chat/src/lib/utils/index.ts +++ b/libs/mobile/chat/features/chat/src/lib/utils/index.ts @@ -1,2 +1,3 @@ export * from './get-siblings-ids'; export * from './patch-new-chat'; +export * from './parse-response-message-content'; diff --git a/libs/mobile/chat/features/chat/src/lib/utils/parse-response-message-content.ts b/libs/mobile/chat/features/chat/src/lib/utils/parse-response-message-content.ts new file mode 100644 index 0000000..5f58d7f --- /dev/null +++ b/libs/mobile/chat/features/chat/src/lib/utils/parse-response-message-content.ts @@ -0,0 +1,206 @@ +import { decode } from 'html-entities'; + +export type ToolData = { + toolName: string; + input: string; + output: string; +}; + +export type ParseResponseMessageContentResult = { + toolsData: ToolData | null; + messageContent: string; +}; + +const readQuotedAttr = (tag: string, attr: string): string | null => { + const needle = `${attr}="`; + const lower = tag.toLowerCase(); + const idx = lower.indexOf(needle.toLowerCase()); + + if (idx === -1) { + return null; + } + + let i = idx + needle.length; + let out = ''; + + while (i < tag.length) { + const c = tag[i]; + + if (c === '\\' && i + 1 < tag.length) { + const esc = tag[i + 1]; + + if (esc === 'n') { + out += '\n'; + } else if (esc === 't') { + out += '\t'; + } else if (esc === 'r') { + out += '\r'; + } else if (esc === '"') { + out += '"'; + } else if (esc === '\\') { + out += '\\'; + } else if (esc === 'u' && /^[0-9a-fA-F]{4}/.test(tag.slice(i + 2, i + 6))) { + out += String.fromCharCode(parseInt(tag.slice(i + 2, i + 6), 16)); + i += 6; + + continue; + } else { + out += esc; + } + + i += 2; + + continue; + } + + if (c === '"') { + break; + } + + out += c; + i++; + } + + return out; +}; + +const indexAfterOpenDetailsTag = (s: string): number => { + const open = s.match(/^<\s*details\b/i); + + if (!open) { + return -1; + } + + let i = open[0].length; + let inDouble = false; + let escape = false; + + while (i < s.length) { + const c = s[i]; + + if (escape) { + escape = false; + i++; + + continue; + } + + if (c === '\\') { + escape = true; + i++; + + continue; + } + + if (c === '"') { + inDouble = !inDouble; + i++; + + continue; + } + + if (c === '>' && !inDouble) { + return i + 1; + } + + i++; + } + + return -1; +}; + +const parseJsonRecursive = (str: string): unknown => { + let cur: unknown = str.trim(); + + for (let depth = 0; depth < 32; depth++) { + if (typeof cur !== 'string') { + return cur; + } + + try { + cur = JSON.parse(cur); + } catch { + return cur; + } + } + + return cur; +}; + +const normalizeToolPayload = (raw: string): string => { + const decoded = decode(raw).trim(); + const parsed = parseJsonRecursive(decoded); + + if (typeof parsed === 'object' && parsed !== null) { + return JSON.stringify(parsed, null, 2); + } + + return String(parsed); +}; + +const repairUtf8MisreadAsLatin1 = (s: string): string => { + for (let j = 0; j < s.length; j++) { + if (s.charCodeAt(j) > 255) { + return s; + } + } + + const bytes = new Uint8Array(s.length); + + for (let j = 0; j < s.length; j++) { + bytes[j] = s.charCodeAt(j); + } + + return new TextDecoder('utf-8', { fatal: false }).decode(bytes); +}; + +const normalizeToolResultText = (s: string): string => { + let t = String(s); + + t = repairUtf8MisreadAsLatin1(t); + + return t; +}; + +export const parseResponseMessageContent = (content: string): ParseResponseMessageContentResult => { + const leadingWs = content.match(/^\s*/)?.[0] ?? ''; + const fromDetails = content.slice(leadingWs.length); + + if (!fromDetails.toLowerCase().startsWith('/i); + + if (!closeMatch || closeMatch.index === undefined) { + return { toolsData: null, messageContent: content }; + } + + const toolName = readQuotedAttr(openTag, 'name') ?? ''; + const argsRaw = readQuotedAttr(openTag, 'arguments') ?? ''; + const resultRaw = readQuotedAttr(openTag, 'result') ?? ''; + + const blockEnd = leadingWs.length + openEnd + closeMatch.index + closeMatch[0].length; + const remainder = content.slice(blockEnd).trimStart(); + + return { + toolsData: { + toolName, + input: normalizeToolPayload(argsRaw), + output: normalizeToolResultText(normalizeToolPayload(resultRaw)), + }, + messageContent: remainder, + }; +}; diff --git a/package-lock.json b/package-lock.json index 419cce0..3d1c60a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -60,6 +60,7 @@ "expo-splash-screen": "~31.0.12", "expo-status-bar": "~3.0.9", "expo-updates": "~29.0.15", + "html-entities": "^2.6.0", "i18n-js": "^4.5.1", "immer": "^10.1.1", "lodash-es": "^4.17.21", @@ -2437,7 +2438,7 @@ "version": "0.2.3", "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/@cspotcode/source-map-support": { @@ -2585,7 +2586,6 @@ "version": "0.21.1", "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz", "integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@eslint/object-schema": "^2.1.7", @@ -2600,7 +2600,6 @@ "version": "0.4.2", "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@eslint/core": "^0.17.0" @@ -2613,7 +2612,6 @@ "version": "0.17.0", "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@types/json-schema": "^7.0.15" @@ -2626,7 +2624,6 @@ "version": "3.3.3", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.3.tgz", "integrity": "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==", - "dev": true, "license": "MIT", "dependencies": { "ajv": "^6.12.4", @@ -2650,7 +2647,6 @@ "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", @@ -2667,14 +2663,12 @@ "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true, "license": "MIT" }, "node_modules/@eslint/js": { "version": "9.39.2", "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.2.tgz", "integrity": "sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==", - "dev": true, "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2687,7 +2681,6 @@ "version": "2.1.7", "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", - "dev": true, "license": "Apache-2.0", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2697,7 +2690,6 @@ "version": "0.4.1", "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@eslint/core": "^0.17.0", @@ -4074,7 +4066,6 @@ "version": "0.19.1", "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", - "dev": true, "license": "Apache-2.0", "engines": { "node": ">=18.18.0" @@ -4084,7 +4075,6 @@ "version": "0.16.7", "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@humanfs/core": "^0.19.1", @@ -4098,7 +4088,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, "license": "Apache-2.0", "engines": { "node": ">=12.22" @@ -4112,7 +4101,6 @@ "version": "0.4.3", "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", - "dev": true, "license": "Apache-2.0", "engines": { "node": ">=18.18" @@ -4349,7 +4337,7 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@jest/types": "^29.6.3", @@ -4367,7 +4355,7 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz", "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@jest/console": "^29.7.0", @@ -4442,7 +4430,7 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz", "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "expect": "^29.7.0", @@ -4456,7 +4444,7 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "jest-get-type": "^29.6.3" @@ -4486,7 +4474,7 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@jest/environment": "^29.7.0", @@ -4502,7 +4490,7 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz", "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@bcoe/v8-coverage": "^0.2.3", @@ -4547,7 +4535,7 @@ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, + "devOptional": true, "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", @@ -4580,7 +4568,7 @@ "version": "29.6.3", "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz", "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "^0.3.18", @@ -4595,7 +4583,7 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz", "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@jest/console": "^29.7.0", @@ -4611,7 +4599,7 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz", "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@jest/test-result": "^29.7.0", @@ -9355,7 +9343,7 @@ "version": "12.9.0", "resolved": "https://registry.npmjs.org/@testing-library/react-native/-/react-native-12.9.0.tgz", "integrity": "sha512-wIn/lB1FjV2N4Q7i9PWVRck3Ehwq5pkhAef5X5/bmQ78J/NoOsGbVY2/DG5Y9Lxw+RfE+GvSEh/fe5Tz6sKSvw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "jest-matcher-utils": "^29.7.0", @@ -9596,7 +9584,6 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", - "dev": true, "license": "MIT" }, "node_modules/@types/express": { @@ -9743,7 +9730,6 @@ "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true, "license": "MIT" }, "node_modules/@types/json5": { @@ -9853,7 +9839,7 @@ "version": "19.1.17", "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.17.tgz", "integrity": "sha512-Qec1E3mhALmaspIrhWt9jkQMNdw6bReVu64mjvhbhq2NFPftLPVr+l1SZgmw/66WwBNpDh7ao5AT6gF5v41PFA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "csstype": "^3.0.2" @@ -10856,7 +10842,6 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, "license": "MIT", "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" @@ -12471,7 +12456,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=10" @@ -12624,7 +12609,7 @@ "version": "1.4.3", "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz", "integrity": "sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/class-transformer": { @@ -12805,7 +12790,7 @@ "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "iojs": ">= 1.0.0", @@ -12823,7 +12808,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.3.tgz", "integrity": "sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/color": { @@ -13232,7 +13217,7 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@jest/types": "^29.6.3", @@ -13656,7 +13641,7 @@ "version": "3.2.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/damerau-levenshtein": { @@ -13788,7 +13773,7 @@ "version": "1.7.0", "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.0.tgz", "integrity": "sha512-HGFtf8yhuhGhqO07SV79tRp+br4MnbdjeVxotpn1QBl30pcLLCQjX5b2295ll0fv8RKDKsmWYrl05usHM9CewQ==", - "dev": true, + "devOptional": true, "license": "MIT", "peerDependencies": { "babel-plugin-macros": "^3.1.0" @@ -13819,7 +13804,6 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true, "license": "MIT" }, "node_modules/deepmerge": { @@ -14033,7 +14017,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=8" @@ -14090,7 +14074,7 @@ "version": "29.6.3", "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" @@ -14306,7 +14290,7 @@ "version": "0.13.1", "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=12" @@ -14344,7 +14328,7 @@ "version": "0.1.13", "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "iconv-lite": "^0.6.2" @@ -14756,7 +14740,6 @@ "version": "9.39.2", "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.2.tgz", "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", - "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", @@ -15125,7 +15108,6 @@ "version": "8.4.0", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", - "dev": true, "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", @@ -15154,7 +15136,6 @@ "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", @@ -15171,14 +15152,12 @@ "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true, "license": "MIT" }, "node_modules/espree": { "version": "10.4.0", "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", - "dev": true, "license": "BSD-2-Clause", "dependencies": { "acorn": "^8.15.0", @@ -15209,7 +15188,6 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", - "dev": true, "license": "BSD-3-Clause", "dependencies": { "estraverse": "^5.1.0" @@ -15222,7 +15200,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, "license": "BSD-2-Clause", "dependencies": { "estraverse": "^5.2.0" @@ -15235,7 +15212,6 @@ "version": "5.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">=4.0" @@ -15245,7 +15221,6 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">=0.10.0" @@ -15408,7 +15383,7 @@ "version": "0.1.2", "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", - "dev": true, + "devOptional": true, "engines": { "node": ">= 0.8.0" } @@ -15430,7 +15405,7 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@jest/expect-utils": "^29.7.0", @@ -17364,7 +17339,6 @@ "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true, "license": "MIT" }, "node_modules/fast-uri": { @@ -17511,7 +17485,6 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", - "dev": true, "license": "MIT", "dependencies": { "flat-cache": "^4.0.0" @@ -17802,7 +17775,6 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", - "dev": true, "license": "MIT", "dependencies": { "flatted": "^3.2.9", @@ -17816,7 +17788,6 @@ "version": "3.3.3", "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", - "dev": true, "license": "ISC" }, "node_modules/flow-enums-runtime": { @@ -18545,7 +18516,6 @@ "version": "14.0.0", "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -18927,11 +18897,27 @@ "node": ">=12" } }, + "node_modules/html-entities": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.6.0.tgz", + "integrity": "sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/mdevils" + }, + { + "type": "patreon", + "url": "https://patreon.com/mdevils" + } + ], + "license": "MIT" + }, "node_modules/html-escaper": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/http-assert": { @@ -19113,7 +19099,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "engines": { "node": ">=10.17.0" @@ -19166,7 +19152,7 @@ "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" @@ -19290,7 +19276,7 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "pkg-dir": "^4.2.0", @@ -19310,7 +19296,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "locate-path": "^5.0.0", @@ -19324,7 +19310,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "p-locate": "^4.1.0" @@ -19337,7 +19323,7 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "p-try": "^2.0.0" @@ -19353,7 +19339,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "p-limit": "^2.2.0" @@ -19366,7 +19352,7 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "find-up": "^4.0.0" @@ -19388,7 +19374,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=8" @@ -19747,7 +19733,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=6" @@ -20197,7 +20183,7 @@ "version": "6.0.3", "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", - "dev": true, + "devOptional": true, "license": "BSD-3-Clause", "dependencies": { "@babel/core": "^7.23.9", @@ -20214,7 +20200,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", - "dev": true, + "devOptional": true, "license": "BSD-3-Clause", "dependencies": { "istanbul-lib-coverage": "^3.0.0", @@ -20229,7 +20215,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", - "dev": true, + "devOptional": true, "license": "BSD-3-Clause", "dependencies": { "debug": "^4.1.1", @@ -20244,7 +20230,7 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", - "dev": true, + "devOptional": true, "license": "BSD-3-Clause", "dependencies": { "html-escaper": "^2.0.0", @@ -20309,7 +20295,7 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@jest/core": "^29.7.0", @@ -20336,7 +20322,7 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz", "integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "execa": "^5.0.0", @@ -20351,7 +20337,7 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "cross-spawn": "^7.0.3", @@ -20375,7 +20361,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=10" @@ -20388,7 +20374,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=8" @@ -20401,7 +20387,7 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "mimic-fn": "^2.1.0" @@ -20417,14 +20403,14 @@ "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true, + "devOptional": true, "license": "ISC" }, "node_modules/jest-circus": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz", "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@jest/environment": "^29.7.0", @@ -20456,7 +20442,7 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz", "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@jest/core": "^29.7.0", @@ -20490,7 +20476,7 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz", "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/core": "^7.11.6", @@ -20537,7 +20523,7 @@ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, + "devOptional": true, "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", @@ -20558,7 +20544,7 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "chalk": "^4.0.0", @@ -20574,7 +20560,7 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz", "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "detect-newline": "^3.0.0" @@ -20587,7 +20573,7 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz", "integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@jest/types": "^29.6.3", @@ -20939,7 +20925,7 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "jest-get-type": "^29.6.3", @@ -20953,7 +20939,7 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "chalk": "^4.0.0", @@ -21017,7 +21003,7 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=6" @@ -21044,7 +21030,7 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "chalk": "^4.0.0", @@ -21065,7 +21051,7 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz", "integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "jest-regex-util": "^29.6.3", @@ -21079,7 +21065,7 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz", "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@jest/console": "^29.7.0", @@ -21112,7 +21098,7 @@ "version": "0.5.13", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "buffer-from": "^1.0.0", @@ -21123,7 +21109,7 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz", "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@jest/environment": "^29.7.0", @@ -21158,7 +21144,7 @@ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, + "devOptional": true, "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", @@ -21179,7 +21165,7 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/core": "^7.11.6", @@ -21387,7 +21373,7 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz", "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@jest/test-result": "^29.7.0", @@ -21584,7 +21570,6 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true, "license": "MIT" }, "node_modules/json-parse-even-better-errors": { @@ -21622,7 +21607,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true, "license": "MIT" }, "node_modules/json5": { @@ -21756,7 +21740,6 @@ "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, "license": "MIT", "dependencies": { "json-buffer": "3.0.1" @@ -22031,7 +22014,6 @@ "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1", @@ -22589,7 +22571,6 @@ "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true, "license": "MIT" }, "node_modules/lodash.throttle": { @@ -22890,7 +22871,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "semver": "^7.5.3" @@ -23866,7 +23847,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=6" @@ -23889,7 +23870,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=4" @@ -24069,7 +24050,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/mkdirp": { @@ -24374,7 +24355,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "path-key": "^3.0.0" @@ -24905,7 +24886,6 @@ "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", - "dev": true, "license": "MIT", "dependencies": { "deep-is": "^0.1.3", @@ -26473,7 +26453,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.8.0" @@ -26696,7 +26675,7 @@ "version": "6.1.0", "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", - "dev": true, + "devOptional": true, "funding": [ { "type": "individual", @@ -27838,7 +27817,7 @@ "version": "19.0.3", "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-19.0.3.tgz", "integrity": "sha512-sGUOsROqjQgnCfimaXgwseQpUm1KdkR0uXQwExLeezjSAqPUUIvcH8+rauWsXye/88AQQguHxSqOfTBluuVQzQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "react-is": "^19.0.3", @@ -27852,14 +27831,14 @@ "version": "0.25.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.25.0.tgz", "integrity": "sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/reactotron-core-client": { "version": "2.9.9", "resolved": "https://registry.npmjs.org/reactotron-core-client/-/reactotron-core-client-2.9.9.tgz", "integrity": "sha512-caI6ZWpfV/gNeCBhm6alxuCpOxYEFxg9FsgVaOXJWZeKjK2egjxkXcUEFWeS3b9mC6Kwi7Wuu79zfeGtkbdAYw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "reactotron-core-contract": "0.3.2" @@ -27869,14 +27848,14 @@ "version": "0.3.2", "resolved": "https://registry.npmjs.org/reactotron-core-contract/-/reactotron-core-contract-0.3.2.tgz", "integrity": "sha512-39ZNLfxxV7WEOszekIRg56F6VFZrQk7+Lei+8MccNESX3VbQzs1uex/GNesxk6CMTS6ytwqYIBAgLyc9WX/PaA==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/reactotron-react-native": { "version": "5.1.18", "resolved": "https://registry.npmjs.org/reactotron-react-native/-/reactotron-react-native-5.1.18.tgz", "integrity": "sha512-Nyb/w7tRQICtfvjAJSN6Q/3aRO8L6eTfEcWpDR/atUyoINkyzducMx6yXA+sz1mazxivY16N3VPkmQ1XohQAcg==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "mitt": "^3.0.1", @@ -27952,7 +27931,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "indent-string": "^4.0.0", @@ -28194,7 +28173,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "resolve-from": "^5.0.0" @@ -28390,7 +28369,6 @@ "version": "7.8.2", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", - "dev": true, "license": "Apache-2.0", "dependencies": { "tslib": "^2.1.0" @@ -28475,7 +28453,7 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/sass": { @@ -29516,7 +29494,7 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "char-regex": "^1.0.2", @@ -29742,7 +29720,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=8" @@ -29762,7 +29740,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=6" @@ -29772,7 +29750,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "min-indent": "^1.0.0" @@ -29785,7 +29763,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -31282,7 +31259,6 @@ "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1" @@ -31415,7 +31391,6 @@ "version": "5.9.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "dev": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", @@ -31730,7 +31705,6 @@ "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, "license": "BSD-2-Clause", "dependencies": { "punycode": "^2.1.0" @@ -31851,7 +31825,7 @@ "version": "9.3.0", "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", - "dev": true, + "devOptional": true, "license": "ISC", "dependencies": { "@jridgewell/trace-mapping": "^0.3.12", @@ -32481,7 +32455,6 @@ "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" diff --git a/package.json b/package.json index e49855a..6f40ebc 100644 --- a/package.json +++ b/package.json @@ -58,6 +58,7 @@ "expo-splash-screen": "~31.0.12", "expo-status-bar": "~3.0.9", "expo-updates": "~29.0.15", + "html-entities": "^2.6.0", "i18n-js": "^4.5.1", "immer": "^10.1.1", "lodash-es": "^4.17.21", From 4b0055f2d534bb68e711d712e826dbf7afacd3f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=B0=D1=81=D0=B8=D0=BB=D0=B8=D0=B9=20=D0=95=D0=BB?= =?UTF-8?q?=D0=B8=D1=81=D0=B5=D0=B5=D0=B2?= Date: Wed, 22 Apr 2026 17:42:36 +0600 Subject: [PATCH 2/7] feat: add parsing array of tools content --- .../lib/components/ai-message/component.tsx | 13 ++++++- .../utils/parse-response-message-content.ts | 39 ++++++++++++++----- 2 files changed, 41 insertions(+), 11 deletions(-) diff --git a/libs/mobile/chat/features/chat/src/lib/components/ai-message/component.tsx b/libs/mobile/chat/features/chat/src/lib/components/ai-message/component.tsx index 27b1654..7fd2908 100644 --- a/libs/mobile/chat/features/chat/src/lib/components/ai-message/component.tsx +++ b/libs/mobile/chat/features/chat/src/lib/components/ai-message/component.tsx @@ -76,8 +76,6 @@ export function ChatAiMessage({ const textWithCitations = prepareTextWithCitations(messageContent, citations); const hasFollowUps = Array.isArray(followUps) && followUps.length > 0; - console.log('toolsData', toolsData); - return ( @@ -89,6 +87,17 @@ export function ChatAiMessage({ {socketStatusData && {socketStatusData.description}} {text ? ( + {toolsData && ( + + {toolsData.map((tool, index) => ( + + {`${tool.toolName}: ${tool.output}`} + + ))} + + )} ; messageContent: string; }; @@ -162,45 +163,65 @@ const normalizeToolResultText = (s: string): string => { return t; }; -export const parseResponseMessageContent = (content: string): ParseResponseMessageContentResult => { +const tryParseLeadingToolCallsDetails = (content: string): { tool: ToolData; rest: string } | null => { const leadingWs = content.match(/^\s*/)?.[0] ?? ''; const fromDetails = content.slice(leadingWs.length); if (!fromDetails.toLowerCase().startsWith('/i); if (!closeMatch || closeMatch.index === undefined) { - return { toolsData: null, messageContent: content }; + return null; } + const id = readQuotedAttr(openTag, 'id') ?? undefined; const toolName = readQuotedAttr(openTag, 'name') ?? ''; const argsRaw = readQuotedAttr(openTag, 'arguments') ?? ''; const resultRaw = readQuotedAttr(openTag, 'result') ?? ''; const blockEnd = leadingWs.length + openEnd + closeMatch.index + closeMatch[0].length; - const remainder = content.slice(blockEnd).trimStart(); + const rest = content.slice(blockEnd).trimStart(); return { - toolsData: { + tool: { + id, toolName, input: normalizeToolPayload(argsRaw), output: normalizeToolResultText(normalizeToolPayload(resultRaw)), }, - messageContent: remainder, + rest, }; }; + +export const parseResponseMessageContent = (content: string): ParseResponseMessageContentResult => { + const toolsData: Array = []; + let rest = content; + + for (;;) { + const next = tryParseLeadingToolCallsDetails(rest); + + if (!next) { + break; + } + + toolsData.push(next.tool); + rest = next.rest; + } + + return { toolsData, messageContent: rest }; +}; From ef34ee0ad16c5d195f1ddc1af8406a2dcbf143c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=B0=D1=81=D0=B8=D0=BB=D0=B8=D0=B9=20=D0=95=D0=BB?= =?UTF-8?q?=D0=B8=D1=81=D0=B5=D0=B5=D0=B2?= Date: Wed, 22 Apr 2026 17:54:52 +0600 Subject: [PATCH 3/7] feat: parse tools response payload content type --- .../src/lib/components/ai-message/component.tsx | 11 ----------- .../lib/utils/parse-response-message-content.ts | 17 ++++++++++++----- 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/libs/mobile/chat/features/chat/src/lib/components/ai-message/component.tsx b/libs/mobile/chat/features/chat/src/lib/components/ai-message/component.tsx index 7fd2908..a99bbbd 100644 --- a/libs/mobile/chat/features/chat/src/lib/components/ai-message/component.tsx +++ b/libs/mobile/chat/features/chat/src/lib/components/ai-message/component.tsx @@ -87,17 +87,6 @@ export function ChatAiMessage({ {socketStatusData && {socketStatusData.description}} {text ? ( - {toolsData && ( - - {toolsData.map((tool, index) => ( - - {`${tool.toolName}: ${tool.output}`} - - ))} - - )} { return cur; }; -const normalizeToolPayload = (raw: string): string => { +const classifyAndNormalizePayload = (raw: string): { contentType: PayloadContentType; normalized: string } => { const decoded = decode(raw).trim(); const parsed = parseJsonRecursive(decoded); if (typeof parsed === 'object' && parsed !== null) { - return JSON.stringify(parsed, null, 2); + return { contentType: 'json', normalized: JSON.stringify(parsed, null, 2) }; } - return String(parsed); + return { contentType: 'text', normalized: String(parsed) }; }; const repairUtf8MisreadAsLatin1 = (s: string): string => { @@ -194,6 +197,9 @@ const tryParseLeadingToolCallsDetails = (content: string): { tool: ToolData; res const argsRaw = readQuotedAttr(openTag, 'arguments') ?? ''; const resultRaw = readQuotedAttr(openTag, 'result') ?? ''; + const inputPayload = classifyAndNormalizePayload(argsRaw); + const outputPayload = classifyAndNormalizePayload(resultRaw); + const blockEnd = leadingWs.length + openEnd + closeMatch.index + closeMatch[0].length; const rest = content.slice(blockEnd).trimStart(); @@ -201,8 +207,9 @@ const tryParseLeadingToolCallsDetails = (content: string): { tool: ToolData; res tool: { id, toolName, - input: normalizeToolPayload(argsRaw), - output: normalizeToolResultText(normalizeToolPayload(resultRaw)), + input: inputPayload.normalized, + output: normalizeToolResultText(outputPayload.normalized), + outputContentType: outputPayload.contentType, }, rest, }; From 7a38a090b92e11c02511ae6eb58a496f1140c5ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=B0=D1=81=D0=B8=D0=BB=D0=B8=D0=B9=20=D0=95=D0=BB?= =?UTF-8?q?=D0=B8=D1=81=D0=B5=D0=B5=D0=B2?= Date: Wed, 22 Apr 2026 18:29:38 +0600 Subject: [PATCH 4/7] feat: add tool response bottom sheet --- i18n/mobile/chat/en.json | 7 ++ .../lib/components/ai-message/component.tsx | 13 ++++ .../tool-output-bottom-sheet/component.tsx | 71 +++++++++++++++++++ .../tool-output-bottom-sheet/index.ts | 1 + 4 files changed, 92 insertions(+) create mode 100644 libs/mobile/chat/features/chat/src/lib/components/tool-output-bottom-sheet/component.tsx create mode 100644 libs/mobile/chat/features/chat/src/lib/components/tool-output-bottom-sheet/index.ts diff --git a/i18n/mobile/chat/en.json b/i18n/mobile/chat/en.json index c969064..9847847 100644 --- a/i18n/mobile/chat/en.json +++ b/i18n/mobile/chat/en.json @@ -156,6 +156,13 @@ }, "MESSAGE_FOLLOW_UPS": { "TEXT_FOLLOW_UP": "Follow up" + }, + "AI_MESSAGE": { + "TOOL_OUTPUT_SHEET": { + "TEXT_VIEW_RESULT_PREFIX": "View result from", + "TEXT_INPUT": "Input", + "TEXT_OUTPUT": "Output" + } } } } diff --git a/libs/mobile/chat/features/chat/src/lib/components/ai-message/component.tsx b/libs/mobile/chat/features/chat/src/lib/components/ai-message/component.tsx index a99bbbd..363134a 100644 --- a/libs/mobile/chat/features/chat/src/lib/components/ai-message/component.tsx +++ b/libs/mobile/chat/features/chat/src/lib/components/ai-message/component.tsx @@ -20,6 +20,7 @@ import { formatDateTime } from '@open-webui-react-native/shared/utils/date'; import { parseResponseMessageContent } from '../../utils'; import { ChatImagesGroup } from '../images'; import { SkeletonMessage } from '../skeleton-message'; +import { ToolOutputBottomSheet } from '../tool-output-bottom-sheet'; interface ChatAiMessageProps { message: Message; @@ -87,6 +88,18 @@ export function ChatAiMessage({ {socketStatusData && {socketStatusData.description}} {text ? ( + {toolsData.length > 0 && ( + + {toolsData.map((tool, index) => ( + + ))} + + )} (null); + + const renderTrigger = ({ onPress }: { onPress: () => void }): ReactNode => ( + + + + {translate('TEXT_VIEW_RESULT_PREFIX')} + {toolName} + + + + ); + + return ( + + sheetRef.current?.close()} /> + + + + {translate('TEXT_INPUT')} + + + {input} + + + {translate('TEXT_OUTPUT')} + + + {output} + + + + + } + /> + ); +} diff --git a/libs/mobile/chat/features/chat/src/lib/components/tool-output-bottom-sheet/index.ts b/libs/mobile/chat/features/chat/src/lib/components/tool-output-bottom-sheet/index.ts new file mode 100644 index 0000000..bb82484 --- /dev/null +++ b/libs/mobile/chat/features/chat/src/lib/components/tool-output-bottom-sheet/index.ts @@ -0,0 +1 @@ +export * from './component'; From 48436bb60e1b26f5748e723ff5f54b79c19ef0e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=B0=D1=81=D0=B8=D0=BB=D0=B8=D0=B9=20=D0=95=D0=BB?= =?UTF-8?q?=D0=B8=D1=81=D0=B5=D0=B5=D0=B2?= Date: Wed, 22 Apr 2026 18:44:14 +0600 Subject: [PATCH 5/7] feat: hide tools response input block if it is empty --- .../tool-output-bottom-sheet/component.tsx | 20 +++++++++++-------- .../utils/parse-response-message-content.ts | 8 ++++++-- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/libs/mobile/chat/features/chat/src/lib/components/tool-output-bottom-sheet/component.tsx b/libs/mobile/chat/features/chat/src/lib/components/tool-output-bottom-sheet/component.tsx index d67c986..ecd3014 100644 --- a/libs/mobile/chat/features/chat/src/lib/components/tool-output-bottom-sheet/component.tsx +++ b/libs/mobile/chat/features/chat/src/lib/components/tool-output-bottom-sheet/component.tsx @@ -1,6 +1,6 @@ import { BottomSheetModal } from '@gorhom/bottom-sheet'; import { useTranslation } from '@ronas-it/react-native-common-modules/i18n'; -import { ReactElement, ReactNode, useRef } from 'react'; +import { Fragment, ReactElement, ReactNode, useRef } from 'react'; import { AppBottomSheet, AppBottomSheetKeyboardAwareScrollView, @@ -14,7 +14,7 @@ import { export interface ToolOutputBottomSheetProps { toolName: string; - input: string; + input?: string; output: string; } @@ -50,12 +50,16 @@ export function ToolOutputBottomSheet({ toolName, input, output }: ToolOutputBot className='flex-1' contentContainerClassName='px-content-offset pb-safe pt-8 android:pb-24'> - - {translate('TEXT_INPUT')} - - - {input} - + {!!input && ( + + + {translate('TEXT_INPUT')} + + + {input} + + + )} {translate('TEXT_OUTPUT')} diff --git a/libs/mobile/chat/features/chat/src/lib/utils/parse-response-message-content.ts b/libs/mobile/chat/features/chat/src/lib/utils/parse-response-message-content.ts index 6fb05d6..740a1b3 100644 --- a/libs/mobile/chat/features/chat/src/lib/utils/parse-response-message-content.ts +++ b/libs/mobile/chat/features/chat/src/lib/utils/parse-response-message-content.ts @@ -1,11 +1,12 @@ import { decode } from 'html-entities'; +import { isEmpty } from 'lodash-es'; type PayloadContentType = 'json' | 'text'; export type ToolData = { id?: string; toolName: string; - input: string; + input: string | undefined; output: string; outputContentType: PayloadContentType; }; @@ -199,6 +200,9 @@ const tryParseLeadingToolCallsDetails = (content: string): { tool: ToolData; res const inputPayload = classifyAndNormalizePayload(argsRaw); const outputPayload = classifyAndNormalizePayload(resultRaw); + const parsedArgs = parseJsonRecursive(decode(argsRaw).trim()); + const input = + typeof parsedArgs === 'object' && parsedArgs !== null && isEmpty(parsedArgs) ? undefined : inputPayload.normalized; const blockEnd = leadingWs.length + openEnd + closeMatch.index + closeMatch[0].length; const rest = content.slice(blockEnd).trimStart(); @@ -207,7 +211,7 @@ const tryParseLeadingToolCallsDetails = (content: string): { tool: ToolData; res tool: { id, toolName, - input: inputPayload.normalized, + input, output: normalizeToolResultText(outputPayload.normalized), outputContentType: outputPayload.contentType, }, From bd9af67a4ade71380c1ae9bb9defa8e4d9431694 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=B0=D1=81=D0=B8=D0=BB=D0=B8=D0=B9=20=D0=95=D0=BB?= =?UTF-8?q?=D0=B8=D1=81=D0=B5=D0=B5=D0=B2?= Date: Wed, 22 Apr 2026 19:17:44 +0600 Subject: [PATCH 6/7] feat: parse object to string for tool response input field --- .../utils/parse-response-message-content.ts | 17 +++++++------- libs/shared/utils/strings/src/index.ts | 1 + .../strings/src/parse-object-to-string.ts | 22 +++++++++++++++++++ 3 files changed, 32 insertions(+), 8 deletions(-) create mode 100644 libs/shared/utils/strings/src/parse-object-to-string.ts diff --git a/libs/mobile/chat/features/chat/src/lib/utils/parse-response-message-content.ts b/libs/mobile/chat/features/chat/src/lib/utils/parse-response-message-content.ts index 740a1b3..cd1f9eb 100644 --- a/libs/mobile/chat/features/chat/src/lib/utils/parse-response-message-content.ts +++ b/libs/mobile/chat/features/chat/src/lib/utils/parse-response-message-content.ts @@ -1,5 +1,5 @@ import { decode } from 'html-entities'; -import { isEmpty } from 'lodash-es'; +import { parseObjectToString } from '@open-webui-react-native/shared/utils/strings'; type PayloadContentType = 'json' | 'text'; @@ -50,7 +50,11 @@ const readQuotedAttr = (tag: string, attr: string): string | null => { continue; } else { - out += esc; + // e.g. `\"` in attributes: keep `\`, let `"` pass through for html decode + out += c; + i += 1; + + continue; } i += 2; @@ -114,8 +118,8 @@ const indexAfterOpenDetailsTag = (s: string): number => { return -1; }; -const parseJsonRecursive = (str: string): unknown => { - let cur: unknown = str.trim(); +const parseJsonRecursive = (str: string): string => { + let cur = str.trim(); for (let depth = 0; depth < 32; depth++) { if (typeof cur !== 'string') { @@ -198,11 +202,8 @@ const tryParseLeadingToolCallsDetails = (content: string): { tool: ToolData; res const argsRaw = readQuotedAttr(openTag, 'arguments') ?? ''; const resultRaw = readQuotedAttr(openTag, 'result') ?? ''; - const inputPayload = classifyAndNormalizePayload(argsRaw); const outputPayload = classifyAndNormalizePayload(resultRaw); - const parsedArgs = parseJsonRecursive(decode(argsRaw).trim()); - const input = - typeof parsedArgs === 'object' && parsedArgs !== null && isEmpty(parsedArgs) ? undefined : inputPayload.normalized; + const input = parseObjectToString(parseJsonRecursive(decode(argsRaw).trim())); const blockEnd = leadingWs.length + openEnd + closeMatch.index + closeMatch[0].length; const rest = content.slice(blockEnd).trimStart(); diff --git a/libs/shared/utils/strings/src/index.ts b/libs/shared/utils/strings/src/index.ts index 4739b61..79ad1a0 100644 --- a/libs/shared/utils/strings/src/index.ts +++ b/libs/shared/utils/strings/src/index.ts @@ -1,2 +1,3 @@ export * from './get-initials'; export * from './get-line-count'; +export * from './parse-object-to-string'; diff --git a/libs/shared/utils/strings/src/parse-object-to-string.ts b/libs/shared/utils/strings/src/parse-object-to-string.ts new file mode 100644 index 0000000..dd1ca62 --- /dev/null +++ b/libs/shared/utils/strings/src/parse-object-to-string.ts @@ -0,0 +1,22 @@ +import { isEmpty } from 'lodash-es'; + +export const parseObjectToString = (parsed: string): string | undefined => { + if (typeof parsed === 'object' && parsed !== null && isEmpty(parsed)) { + return undefined; + } + + if (typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed)) { + return Object.entries(parsed) + .map( + ([key, value]) => + `${key}\n${typeof value === 'object' && value !== null ? JSON.stringify(value) : String(value)}`, + ) + .join('\n\n'); + } + + if (typeof parsed === 'object' && parsed !== null) { + return JSON.stringify(parsed, null, 2); + } + + return String(parsed); +}; From 04194db17c3fa9fadd26ef0d4290bf361a259e64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=B0=D1=81=D0=B8=D0=BB=D0=B8=D0=B9=20=D0=95=D0=BB?= =?UTF-8?q?=D0=B8=D1=81=D0=B5=D0=B5=D0=B2?= Date: Thu, 23 Apr 2026 15:25:25 +0600 Subject: [PATCH 7/7] refactor: parse tool response content adjustments --- .../lib/components/ai-message/component.tsx | 2 +- .../tool-output-bottom-sheet/component.tsx | 10 +- .../utils/parse-response-message-content.ts | 122 +++++------------- 3 files changed, 39 insertions(+), 95 deletions(-) diff --git a/libs/mobile/chat/features/chat/src/lib/components/ai-message/component.tsx b/libs/mobile/chat/features/chat/src/lib/components/ai-message/component.tsx index 363134a..b71b7ad 100644 --- a/libs/mobile/chat/features/chat/src/lib/components/ai-message/component.tsx +++ b/libs/mobile/chat/features/chat/src/lib/components/ai-message/component.tsx @@ -67,7 +67,7 @@ export function ChatAiMessage({ file.type === FileType.IMAGE ? [...acc, { type: file.type, url: `${apiUrl}${file.url}`, index }] : acc, [] as Array, ), - [files], + [apiUrl, files], ); const { handleImagePress, handleAllPhotosPress, selectedImageIndex, isPreviewVisible, handleCloseImagePress } = diff --git a/libs/mobile/chat/features/chat/src/lib/components/tool-output-bottom-sheet/component.tsx b/libs/mobile/chat/features/chat/src/lib/components/tool-output-bottom-sheet/component.tsx index ecd3014..10c231f 100644 --- a/libs/mobile/chat/features/chat/src/lib/components/tool-output-bottom-sheet/component.tsx +++ b/libs/mobile/chat/features/chat/src/lib/components/tool-output-bottom-sheet/component.tsx @@ -1,9 +1,8 @@ -import { BottomSheetModal } from '@gorhom/bottom-sheet'; +import { BottomSheetModal, BottomSheetScrollView } from '@gorhom/bottom-sheet'; import { useTranslation } from '@ronas-it/react-native-common-modules/i18n'; import { Fragment, ReactElement, ReactNode, useRef } from 'react'; import { AppBottomSheet, - AppBottomSheetKeyboardAwareScrollView, AppPressable, AppSafeAreaView, AppText, @@ -41,14 +40,11 @@ export function ToolOutputBottomSheet({ toolName, input, output }: ToolOutputBot isModal={true} isScrollable={true} snapPoints={['100%']} - className='px-0' renderTrigger={renderTrigger} content={ sheetRef.current?.close()} /> - + {!!input && ( @@ -67,7 +63,7 @@ export function ToolOutputBottomSheet({ toolName, input, output }: ToolOutputBot {output} - + } /> diff --git a/libs/mobile/chat/features/chat/src/lib/utils/parse-response-message-content.ts b/libs/mobile/chat/features/chat/src/lib/utils/parse-response-message-content.ts index cd1f9eb..5cad660 100644 --- a/libs/mobile/chat/features/chat/src/lib/utils/parse-response-message-content.ts +++ b/libs/mobile/chat/features/chat/src/lib/utils/parse-response-message-content.ts @@ -16,61 +16,39 @@ export type ParseResponseMessageContentResult = { messageContent: string; }; -const readQuotedAttr = (tag: string, attr: string): string | null => { - const needle = `${attr}="`; - const lower = tag.toLowerCase(); - const idx = lower.indexOf(needle.toLowerCase()); - - if (idx === -1) { - return null; - } - - let i = idx + needle.length; - let out = ''; - - while (i < tag.length) { - const c = tag[i]; - - if (c === '\\' && i + 1 < tag.length) { - const esc = tag[i + 1]; - - if (esc === 'n') { - out += '\n'; - } else if (esc === 't') { - out += '\t'; - } else if (esc === 'r') { - out += '\r'; - } else if (esc === '"') { - out += '"'; - } else if (esc === '\\') { - out += '\\'; - } else if (esc === 'u' && /^[0-9a-fA-F]{4}/.test(tag.slice(i + 2, i + 6))) { - out += String.fromCharCode(parseInt(tag.slice(i + 2, i + 6), 16)); - i += 6; - - continue; - } else { - // e.g. `\"` in attributes: keep `\`, let `"` pass through for html decode - out += c; - i += 1; - - continue; - } - - i += 2; - - continue; +const unescapeAttributeValue = (value: string): string => + value.replace(/\\(u[0-9a-fA-F]{4}|["'\\ntr])/g, (_, esc: string) => { + switch (esc) { + case 'n': + return '\n'; + case 't': + return '\t'; + case 'r': + return '\r'; + case '"': + return '"'; + case '\'': + return '\''; + case '\\': + return '\\'; + default: + return esc.startsWith('u') ? String.fromCharCode(parseInt(esc.slice(1), 16)) : esc; } + }); - if (c === '"') { - break; - } +const parseTagAttributes = (tag: string): Record => { + const attrs: Record = {}; + const attrRe = /([^\s=/>]+)\s*=\s*(?:"((?:\\.|[^"])*)"|'((?:\\.|[^'])*)')/g; - out += c; - i++; + let match: RegExpExecArray | null; + + while ((match = attrRe.exec(tag)) !== null) { + const [, rawName, doubleQuoted, singleQuoted] = match; + const rawValue = doubleQuoted ?? singleQuoted ?? ''; + attrs[rawName.toLowerCase()] = unescapeAttributeValue(rawValue); } - return out; + return attrs; }; const indexAfterOpenDetailsTag = (s: string): number => { @@ -79,7 +57,6 @@ const indexAfterOpenDetailsTag = (s: string): number => { if (!open) { return -1; } - let i = open[0].length; let inDouble = false; let escape = false; @@ -90,28 +67,24 @@ const indexAfterOpenDetailsTag = (s: string): number => { if (escape) { escape = false; i++; - continue; } if (c === '\\') { escape = true; i++; - continue; } if (c === '"') { inDouble = !inDouble; i++; - continue; } if (c === '>' && !inDouble) { return i + 1; } - i++; } @@ -147,30 +120,6 @@ const classifyAndNormalizePayload = (raw: string): { contentType: PayloadContent return { contentType: 'text', normalized: String(parsed) }; }; -const repairUtf8MisreadAsLatin1 = (s: string): string => { - for (let j = 0; j < s.length; j++) { - if (s.charCodeAt(j) > 255) { - return s; - } - } - - const bytes = new Uint8Array(s.length); - - for (let j = 0; j < s.length; j++) { - bytes[j] = s.charCodeAt(j); - } - - return new TextDecoder('utf-8', { fatal: false }).decode(bytes); -}; - -const normalizeToolResultText = (s: string): string => { - let t = String(s); - - t = repairUtf8MisreadAsLatin1(t); - - return t; -}; - const tryParseLeadingToolCallsDetails = (content: string): { tool: ToolData; rest: string } | null => { const leadingWs = content.match(/^\s*/)?.[0] ?? ''; const fromDetails = content.slice(leadingWs.length); @@ -186,8 +135,9 @@ const tryParseLeadingToolCallsDetails = (content: string): { tool: ToolData; res } const openTag = fromDetails.slice(0, openEnd); + const attrs = parseTagAttributes(openTag); - if (!/type\s*=\s*["']?tool_calls["']?/i.test(openTag)) { + if ((attrs.type ?? '').toLowerCase() !== 'tool_calls') { return null; } @@ -197,14 +147,13 @@ const tryParseLeadingToolCallsDetails = (content: string): { tool: ToolData; res return null; } - const id = readQuotedAttr(openTag, 'id') ?? undefined; - const toolName = readQuotedAttr(openTag, 'name') ?? ''; - const argsRaw = readQuotedAttr(openTag, 'arguments') ?? ''; - const resultRaw = readQuotedAttr(openTag, 'result') ?? ''; + const id = attrs.id ?? undefined; + const toolName = attrs.name ?? ''; + const argsRaw = attrs.arguments ?? ''; + const resultRaw = attrs.result ?? ''; const outputPayload = classifyAndNormalizePayload(resultRaw); const input = parseObjectToString(parseJsonRecursive(decode(argsRaw).trim())); - const blockEnd = leadingWs.length + openEnd + closeMatch.index + closeMatch[0].length; const rest = content.slice(blockEnd).trimStart(); @@ -213,7 +162,7 @@ const tryParseLeadingToolCallsDetails = (content: string): { tool: ToolData; res id, toolName, input, - output: normalizeToolResultText(outputPayload.normalized), + output: outputPayload.normalized, outputContentType: outputPayload.contentType, }, rest, @@ -230,7 +179,6 @@ export const parseResponseMessageContent = (content: string): ParseResponseMessa if (!next) { break; } - toolsData.push(next.tool); rest = next.rest; }