From d2d4e1cbac00a7ca934a47c4dd7e4f5600227136 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sun, 29 Mar 2026 13:03:05 +0300 Subject: [PATCH] refactor(llm): use vercel/AI instead --- apps/server/package.json | 3 +- .../src/services/llm/providers/anthropic.ts | 180 +++++++++--------- pnpm-lock.yaml | 143 ++++++++------ 3 files changed, 174 insertions(+), 152 deletions(-) diff --git a/apps/server/package.json b/apps/server/package.json index 7cb490023f..76d0c06dec 100644 --- a/apps/server/package.json +++ b/apps/server/package.json @@ -30,7 +30,8 @@ "proxy-nginx-subdir": "docker run --name trilium-nginx-subdir --rm --network=host -v ./docker/nginx.conf:/etc/nginx/conf.d/default.conf:ro nginx:latest" }, "dependencies": { - "@anthropic-ai/sdk": "^0.39.0", + "@ai-sdk/anthropic": "^2.0.0", + "ai": "^5.0.0", "better-sqlite3": "12.8.0", "html-to-text": "9.0.5", "node-html-parser": "7.1.0", diff --git a/apps/server/src/services/llm/providers/anthropic.ts b/apps/server/src/services/llm/providers/anthropic.ts index 5f217a15ec..2b1f9d2e92 100644 --- a/apps/server/src/services/llm/providers/anthropic.ts +++ b/apps/server/src/services/llm/providers/anthropic.ts @@ -1,4 +1,5 @@ -import Anthropic from "@anthropic-ai/sdk"; +import { anthropic } from "@ai-sdk/anthropic"; +import { streamText, type CoreMessage } from "ai"; import type { LlmMessage, LlmStreamChunk } from "@triliumnext/commons"; import type { LlmProvider, LlmProviderConfig } from "../types.js"; @@ -6,26 +7,15 @@ import type { LlmProvider, LlmProviderConfig } from "../types.js"; const DEFAULT_MODEL = "claude-sonnet-4-20250514"; const DEFAULT_MAX_TOKENS = 8096; -/** - * Server-side web search tool type. - * Not yet in SDK types as of @anthropic-ai/sdk. - */ -interface WebSearchTool { - type: "web_search_20250305"; - name: "web_search"; - max_uses?: number; -} - export class AnthropicProvider implements LlmProvider { name = "anthropic"; - private client: Anthropic; constructor() { const apiKey = process.env.ANTHROPIC_API_KEY; if (!apiKey) { throw new Error("ANTHROPIC_API_KEY environment variable is required"); } - this.client = new Anthropic({ apiKey }); + // The anthropic provider reads ANTHROPIC_API_KEY from env automatically } async *streamCompletion( @@ -35,101 +25,105 @@ export class AnthropicProvider implements LlmProvider { const systemPrompt = config.systemPrompt || messages.find(m => m.role === "system")?.content; const chatMessages = messages.filter(m => m.role !== "system"); - // Build tools array - // Using union with WebSearchTool since it's not in SDK types yet - const tools: (Anthropic.ToolUnion | WebSearchTool)[] = []; - if (config.enableWebSearch) { - tools.push({ - type: "web_search_20250305", - name: "web_search", - max_uses: 5 // Limit searches per request - } satisfies WebSearchTool); - } + // Convert to AI SDK message format + const coreMessages: CoreMessage[] = chatMessages.map(m => ({ + role: m.role as "user" | "assistant", + content: m.content + })); try { - const streamParams: Anthropic.Messages.MessageStreamParams = { - model: config.model || DEFAULT_MODEL, - max_tokens: config.maxTokens || DEFAULT_MAX_TOKENS, - system: systemPrompt, - messages: chatMessages.map(m => ({ - role: m.role as "user" | "assistant", - content: m.content - })) - }; + const model = anthropic(config.model || DEFAULT_MODEL); - if (tools.length > 0) { - // Cast needed until SDK adds WebSearchTool type - streamParams.tools = tools as Anthropic.ToolUnion[]; - } + // Build options for streamText + const streamOptions: Parameters[0] = { + model, + messages: coreMessages, + maxOutputTokens: config.maxTokens || DEFAULT_MAX_TOKENS, + system: systemPrompt + }; // Enable extended thinking for deeper reasoning if (config.enableExtendedThinking) { const thinkingBudget = config.thinkingBudget || 10000; - // max_tokens must be greater than thinking budget - streamParams.max_tokens = Math.max(streamParams.max_tokens, thinkingBudget + 4000); - streamParams.thinking = { - type: "enabled", - budget_tokens: thinkingBudget + // Vercel AI SDK handles thinking via providerOptions + streamOptions.providerOptions = { + anthropic: { + thinking: { + type: "enabled", + budgetTokens: thinkingBudget + } + } }; + // Ensure max tokens accommodates thinking budget + streamOptions.maxOutputTokens = Math.max( + streamOptions.maxOutputTokens || DEFAULT_MAX_TOKENS, + thinkingBudget + 4000 + ); console.log(`[LLM] Extended thinking enabled with budget: ${thinkingBudget} tokens`); } - const stream = this.client.messages.stream(streamParams); - - for await (const event of stream) { - // Handle different event types - if (event.type === "content_block_start") { - const block = event.content_block; - if (block.type === "tool_use") { - yield { - type: "tool_use", - toolName: block.name, - toolInput: {} // Input comes in deltas - }; - } else if (block.type === "thinking") { - console.log("[LLM] Thinking block started"); - } - } else if (event.type === "content_block_delta") { - const delta = event.delta; - if (delta.type === "text_delta") { - yield { type: "text", content: delta.text }; - } else if (delta.type === "thinking_delta") { - yield { type: "thinking", content: delta.thinking }; - } else if (delta.type === "input_json_delta") { - // Tool input is being streamed - we could accumulate it - // For now, we already emitted tool_use at start - } - } else if (event.type === "content_block_stop") { - // Content block finished - // For server-side tools, results come in subsequent blocks - } - - // Handle server-side tool results (for web_search) - // These appear as special content blocks in the response - if (event.type === "message_delta") { - // Check for citations in stop_reason or other metadata - } + // Enable web search if configured + if (config.enableWebSearch) { + const webSearchTool = anthropic.tools.webSearch_20250305({ + maxUses: 5 + }); + streamOptions.tools = { + web_search: webSearchTool + }; } - // Get the final message to extract any citations - const finalMessage = await stream.finalMessage(); - for (const block of finalMessage.content) { - if (block.type === "text" && block.citations) { - for (const citation of block.citations) { - // Extract citation info from SDK types (CitationCharLocation, etc.) - // These have: cited_text, document_index, document_title - // Web search citations may have additional properties at runtime - const citationData = citation as unknown as Record; + const result = streamText(streamOptions); + + // Stream the response + for await (const part of result.fullStream) { + switch (part.type) { + case "text-delta": + yield { type: "text", content: part.text }; + break; + + case "reasoning-delta": + // Extended thinking content + yield { type: "thinking", content: part.text }; + break; + + case "tool-call": yield { - type: "citation", - citation: { - title: citation.document_title ?? undefined, - citedText: citation.cited_text, - // URL may be present for web search results (not in SDK types yet) - url: typeof citationData.url === "string" ? citationData.url : undefined - } + type: "tool_use", + toolName: part.toolName, + toolInput: part.input as Record }; - } + break; + + case "tool-result": + yield { + type: "tool_result", + toolName: part.toolName, + result: typeof part.output === "string" + ? part.output + : JSON.stringify(part.output) + }; + break; + + case "source": + // Citation from web search (only URL sources have url property) + if (part.sourceType === "url") { + yield { + type: "citation", + citation: { + url: part.url, + title: part.title + } + }; + } + break; + + case "error": + yield { type: "error", error: String(part.error) }; + break; + + case "finish": + // Stream finished + break; } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6e17d4fdc8..a0fbf58129 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -552,9 +552,12 @@ importers: apps/server: dependencies: - '@anthropic-ai/sdk': - specifier: ^0.39.0 - version: 0.39.0(encoding@0.1.13) + '@ai-sdk/anthropic': + specifier: ^2.0.0 + version: 2.0.71(zod@4.1.12) + ai: + specifier: ^5.0.0 + version: 5.0.161(zod@4.1.12) better-sqlite3: specifier: 12.8.0 version: 12.8.0 @@ -1529,6 +1532,28 @@ packages: '@adobe/css-tools@4.4.4': resolution: {integrity: sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg==} + '@ai-sdk/anthropic@2.0.71': + resolution: {integrity: sha512-JXTtAwlyxGzzRtpiAXk/O93aOTgdfoVX28EoUuRNVqZRgtkoniLQTtqeb8uZ4oXljNJlXzaJLNasS/U90w/wjw==} + engines: {node: '>=18'} + peerDependencies: + zod: ^3.25.76 || ^4.1.8 + + '@ai-sdk/gateway@2.0.65': + resolution: {integrity: sha512-yaWzvQQWgAzV0m3eidfpRub1+PggDOr2hLnSOI+L2ZispyJ/7EoSzhjKzNCADj6PHnnPaOMH933Xhl1Z/NSxJw==} + engines: {node: '>=18'} + peerDependencies: + zod: ^3.25.76 || ^4.1.8 + + '@ai-sdk/provider-utils@3.0.22': + resolution: {integrity: sha512-fFT1KfUUKktfAFm5mClJhS1oux9tP2qgzmEZVl5UdwltQ1LO/s8hd7znVrgKzivwv1s1FIPza0s9OpJaNB/vHw==} + engines: {node: '>=18'} + peerDependencies: + zod: ^3.25.76 || ^4.1.8 + + '@ai-sdk/provider@2.0.1': + resolution: {integrity: sha512-KCUwswvsC5VsW2PWFqF8eJgSCu5Ysj7m1TxiHTVA6g7k360bk0RNQENT8KTMAYEs+8fWPD3Uu4dEmzGHc+jGng==} + engines: {node: '>=18'} + '@aklinker1/rollup-plugin-visualizer@5.12.0': resolution: {integrity: sha512-X24LvEGw6UFmy0lpGJDmXsMyBD58XmX1bbwsaMLhNoM+UMQfQ3b2RtC+nz4b/NoRK5r6QJSKJHBNVeUdwqybaQ==} engines: {node: '>=14'} @@ -1546,9 +1571,6 @@ packages: '@antfu/install-pkg@1.1.0': resolution: {integrity: sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ==} - '@anthropic-ai/sdk@0.39.0': - resolution: {integrity: sha512-eMyDIPRZbt1CCLErRCi3exlAvNkBtRe+kW5vvJyef93PmNr/clstYgHhtvmkxN82nlKgzyGPCyGxrm0JQ1ZIdg==} - '@apidevtools/json-schema-ref-parser@9.1.2': resolution: {integrity: sha512-r1w81DpR+KyRWd3f+rk6TNqMgedmAxZP5v5KWlXQWlgMUUtyEJch0DKEci1SorPMiSeM8XPl7MZ3miJ60JIpQg==} @@ -6179,18 +6201,12 @@ packages: '@types/mute-stream@0.0.4': resolution: {integrity: sha512-CPM9nzrCPPJHQNA9keH9CVkVI+WR5kMa+7XEs5jcGQ0VoAGnLv242w8lIVgwAEfmE4oufJRaTc9PNLQl0ioAow==} - '@types/node-fetch@2.6.13': - resolution: {integrity: sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw==} - '@types/node-forge@1.3.14': resolution: {integrity: sha512-mhVF2BnD4BO+jtOp7z1CdzaK4mbuK0LLQYAvdOLqHTavxFNq4zA1EmYkpnFjP8HOUzedfQkRnp0E2ulSAYSzAw==} '@types/node@16.9.1': resolution: {integrity: sha512-QpLcX9ZSsq3YYUUnD3nFDY8H7wctAhQj/TFKL8Ya8v5fMm3CFXxo8zStsLAl780ltoYoo1WvKUVGBQK+1ifr7g==} - '@types/node@18.19.130': - resolution: {integrity: sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg==} - '@types/node@20.19.25': resolution: {integrity: sha512-ZsJzA5thDQMSQO788d7IocwwQbI8B5OPzmqNvpf3NY/+MHDAS759Wo0gd2WQeXYt5AAAQjzcrTVC6SKCuYgoCQ==} @@ -7015,6 +7031,10 @@ packages: '@upsetjs/venn.js@2.0.0': resolution: {integrity: sha512-WbBhLrooyePuQ1VZxrJjtLvTc4NVfpOyKx0sKqioq9bX1C1m7Jgykkn8gLrtwumBioXIqam8DLxp88Adbue6Hw==} + '@vercel/oidc@3.1.0': + resolution: {integrity: sha512-Fw28YZpRnA3cAHHDlkt7xQHiJ0fcL+NRcIqsocZQUSmbzeIKRpwttJjik5ZGanXP+vlA4SbTg+AbA3bP363l+w==} + engines: {node: '>= 20'} + '@vitest/browser-webdriverio@4.1.2': resolution: {integrity: sha512-5VKfMSq6ZoEAmvVu3sJGkDjEjGuxwk72tOgoNJfJYv+c+UQX1D4UqSdL8kXUMJcTQx1tKeWwQ9Zym0gRdMfyrA==} peerDependencies: @@ -7325,6 +7345,12 @@ packages: resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} engines: {node: '>=8'} + ai@5.0.161: + resolution: {integrity: sha512-CVANs7auUNEi/hRhdJDKcPYaCLWXveIfmoiekNSRel3i8WUieB6iEncDS5smcubWsx7hGtTgXxNRTg0YG0ljtA==} + engines: {node: '>=18'} + peerDependencies: + zod: ^3.25.76 || ^4.1.8 + ajv-draft-04@1.0.0: resolution: {integrity: sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==} peerDependencies: @@ -9477,6 +9503,10 @@ packages: resolution: {integrity: sha512-6RxOBZ/cYgd8usLwsEl+EC09Au/9BcmCKYF2/xbml6DNczf7nv0MQb+7BA2F+li6//I+28VNlQR37XfQtcAJuA==} engines: {node: '>=18.0.0'} + eventsource-parser@3.0.6: + resolution: {integrity: sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==} + engines: {node: '>=18.0.0'} + execa@1.0.0: resolution: {integrity: sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==} engines: {node: '>=6'} @@ -9741,9 +9771,6 @@ packages: foreach@2.0.6: resolution: {integrity: sha512-k6GAGDyqLe9JaebCsFCoudPPWfihKu8pylYXRlqP1J7ms39iPoTtk2fviNglIeQEwdh0bQeKJ01ZPyuyQvKzwg==} - form-data-encoder@1.7.2: - resolution: {integrity: sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==} - form-data-encoder@4.1.0: resolution: {integrity: sha512-G6NsmEW15s0Uw9XnCg+33H3ViYRyiM0hMrMhhqQOR8NFc5GhYrI+6I3u7OTw7b91J2g8rtvMBZJDbcGb2YUniw==} engines: {node: '>= 18'} @@ -9756,10 +9783,6 @@ packages: resolution: {integrity: sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==} engines: {node: '>=0.4.x'} - formdata-node@4.4.1: - resolution: {integrity: sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==} - engines: {node: '>= 12.20'} - formdata-node@6.0.3: resolution: {integrity: sha512-8e1++BCiTzUno9v5IZ2J6bv4RU+3UKDmqWUQD0MIMVCd9AdhWkO1gw57oo1mNEX1dMq2EGI+FbWz4B92pscSQg==} engines: {node: '>= 18'} @@ -11020,6 +11043,9 @@ packages: json-schema-traverse@1.0.0: resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + json-schema@0.4.0: + resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==} + json-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} @@ -15044,9 +15070,6 @@ packages: resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} engines: {node: '>= 0.4'} - undici-types@5.26.5: - resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} - undici-types@6.21.0: resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} @@ -15552,10 +15575,6 @@ packages: resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==} engines: {node: '>= 8'} - web-streams-polyfill@4.0.0-beta.3: - resolution: {integrity: sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==} - engines: {node: '>= 14'} - webdriver@9.27.0: resolution: {integrity: sha512-w07ThZND48SIr0b4S7eFougYUyclmoUwdmju8yXvEJiXYjDjeYUpl8wZrYPEYRBylxpSx+sBHfEUBrPQkcTTRQ==} engines: {node: '>=18.20.0'} @@ -16003,6 +16022,30 @@ snapshots: '@adobe/css-tools@4.4.4': {} + '@ai-sdk/anthropic@2.0.71(zod@4.1.12)': + dependencies: + '@ai-sdk/provider': 2.0.1 + '@ai-sdk/provider-utils': 3.0.22(zod@4.1.12) + zod: 4.1.12 + + '@ai-sdk/gateway@2.0.65(zod@4.1.12)': + dependencies: + '@ai-sdk/provider': 2.0.1 + '@ai-sdk/provider-utils': 3.0.22(zod@4.1.12) + '@vercel/oidc': 3.1.0 + zod: 4.1.12 + + '@ai-sdk/provider-utils@3.0.22(zod@4.1.12)': + dependencies: + '@ai-sdk/provider': 2.0.1 + '@standard-schema/spec': 1.1.0 + eventsource-parser: 3.0.6 + zod: 4.1.12 + + '@ai-sdk/provider@2.0.1': + dependencies: + json-schema: 0.4.0 + '@aklinker1/rollup-plugin-visualizer@5.12.0(rollup@4.52.0)': dependencies: open: 8.4.2 @@ -16022,18 +16065,6 @@ snapshots: package-manager-detector: 1.3.0 tinyexec: 1.0.4 - '@anthropic-ai/sdk@0.39.0(encoding@0.1.13)': - dependencies: - '@types/node': 18.19.130 - '@types/node-fetch': 2.6.13 - abort-controller: 3.0.0 - agentkeepalive: 4.6.0 - form-data-encoder: 1.7.2 - formdata-node: 4.4.1 - node-fetch: 2.7.0(encoding@0.1.13) - transitivePeerDependencies: - - encoding - '@apidevtools/json-schema-ref-parser@9.1.2': dependencies: '@jsdevtools/ono': 7.1.3 @@ -17558,6 +17589,8 @@ snapshots: '@ckeditor/ckeditor5-utils': 47.6.1 ckeditor5: 47.6.1 es-toolkit: 1.39.5 + transitivePeerDependencies: + - supports-color '@ckeditor/ckeditor5-merge-fields@47.6.1': dependencies: @@ -22302,21 +22335,12 @@ snapshots: dependencies: '@types/node': 24.12.0 - '@types/node-fetch@2.6.13': - dependencies: - '@types/node': 24.12.0 - form-data: 4.0.5 - '@types/node-forge@1.3.14': dependencies: '@types/node': 24.12.0 '@types/node@16.9.1': {} - '@types/node@18.19.130': - dependencies: - undici-types: 5.26.5 - '@types/node@20.19.25': dependencies: undici-types: 6.21.0 @@ -24086,6 +24110,8 @@ snapshots: d3-selection: 3.0.0 d3-transition: 3.0.1(d3-selection@3.0.0) + '@vercel/oidc@3.1.0': {} + '@vitest/browser-webdriverio@4.1.2(bufferutil@4.0.9)(msw@2.7.5(@types/node@24.12.0)(typescript@5.9.3))(utf-8-validate@6.0.5)(vite@8.0.3(@types/node@24.12.0)(esbuild@0.27.4)(jiti@2.6.1)(less@4.1.3)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.2))(vitest@4.1.2)(webdriverio@9.27.0(bufferutil@4.0.9)(utf-8-validate@6.0.5))': dependencies: '@vitest/browser': 4.1.2(bufferutil@4.0.9)(msw@2.7.5(@types/node@24.12.0)(typescript@5.9.3))(utf-8-validate@6.0.5)(vite@8.0.3(@types/node@24.12.0)(esbuild@0.27.4)(jiti@2.6.1)(less@4.1.3)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.2))(vitest@4.1.2) @@ -24498,6 +24524,14 @@ snapshots: clean-stack: 2.2.0 indent-string: 4.0.0 + ai@5.0.161(zod@4.1.12): + dependencies: + '@ai-sdk/gateway': 2.0.65(zod@4.1.12) + '@ai-sdk/provider': 2.0.1 + '@ai-sdk/provider-utils': 3.0.22(zod@4.1.12) + '@opentelemetry/api': 1.9.0 + zod: 4.1.12 + ajv-draft-04@1.0.0(ajv@8.13.0): optionalDependencies: ajv: 8.13.0 @@ -27236,6 +27270,8 @@ snapshots: eventsource-parser@3.0.2: {} + eventsource-parser@3.0.6: {} + execa@1.0.0: dependencies: cross-spawn: 6.0.6 @@ -27642,8 +27678,6 @@ snapshots: foreach@2.0.6: {} - form-data-encoder@1.7.2: {} - form-data-encoder@4.1.0: {} form-data@4.0.5: @@ -27656,11 +27690,6 @@ snapshots: format@0.2.2: {} - formdata-node@4.4.1: - dependencies: - node-domexception: 1.0.0 - web-streams-polyfill: 4.0.0-beta.3 - formdata-node@6.0.3: {} formdata-polyfill@4.0.10: @@ -29057,6 +29086,8 @@ snapshots: json-schema-traverse@1.0.0: {} + json-schema@0.4.0: {} + json-stable-stringify-without-jsonify@1.0.1: {} json-stringify-pretty-compact@4.0.0: {} @@ -33907,8 +33938,6 @@ snapshots: has-symbols: 1.1.0 which-boxed-primitive: 1.1.1 - undici-types@5.26.5: {} - undici-types@6.21.0: {} undici-types@7.16.0: {} @@ -34423,8 +34452,6 @@ snapshots: web-streams-polyfill@3.3.3: {} - web-streams-polyfill@4.0.0-beta.3: {} - webdriver@9.27.0(bufferutil@4.0.9)(utf-8-validate@6.0.5): dependencies: '@types/node': 20.19.25