🔒️ Upgrade vulnerable deps (ai v5, nodemailer v8, otel sdk-node 0.217) (#2491)

## Summary

Fixes 18 open Dependabot alerts and migrates affected code to the new
major versions:

- `@opentelemetry/sdk-node` → `^0.217.0` (Prometheus exporter DoS,
GHSA-q7rr-3cgh-j5r3)
- `nodemailer` → `^8.0.5` across all manifests + root override
(GHSA-vvjj-xcjg-gr5g, GHSA-c7w3-x93f-qmm8)
- `ai` → `^5.0.52` (GHSA-rwvc-j5jr-mgvh); legacy 3.x dep removed from
`packages/deprecated/legacy` and replaced with a small in-tree
`OpenAIStream` + `StreamingTextResponse` shim
- Provider SDKs aligned to v5 peer: `@ai-sdk/openai`, `anthropic`,
`groq`, `mistral`, `perplexity`, `deepseek`, `togetherai`, `openRouter`,
`dify-ai-provider`

### AI SDK v4 → v5 migration

- `parseTools`: `parameters` renamed to `inputSchema`
- `runChatCompletion` / `runChatCompletionStream`: `maxSteps` replaced
by `stopWhen(stepCountIs(maxSteps))`;
`usage.{prompt,completion,total}Tokens` replaced by
`totalUsage.{input,output,total}Tokens`
- New `toLegacyDataStream` helper that re-emits the v4 data-stream
protocol (`0:text`, `3:error`, `9:tool_call`, …) so existing consumers
in `embeds/js` and the OpenAI `askAssistant` / `askModel` handlers keep
working
- `compatibility: "strict"` removed from `createOpenAI` (option dropped
in v5)
- `formatDataStreamPart` / `processDataStream` imports moved to
`@ai-sdk/ui-utils` (legacy package pinned at 1.2.11)

### E2E test follow-up

Second commit fixes Playwright tests that broke once the env-resolved
URLs / new SDK surface kicked in:
- `fileUpload`: assert exported URL contains `parseS3PublicBaseUrl()`
(not `S3_ENDPOINT`) so it works with `S3_PUBLIC_CUSTOM_DOMAIN`; verify
post-deletion via cache-busted `request.get` instead of a CDN-cached new
tab.
- `ssrf`: assert on the actual "Security validation failed" log emitted
by the pre-flight check; fixture now maps `response.statusCode` into a
`Status` variable so `Status: …` assertions resolve.
- Root `dev` script includes `@typebot.io/partykit` so the webhook
listener e2e test can hit PartyKit on `:1999`.

Also fixes a pre-existing broken anchor link in `whatsapp-ai-agent.mdx`
that blocked the landing-page link checker.

## Test plan

- [ ] `bunx nx test` passes
- [ ] `bunx nx typecheck` passes
- [ ] `bunx nx affected -t
format-and-lint,lint-repo,check-broken-links,test --parallel=4` passes
(pre-commit)
- [ ] `bun run dev` boots builder, viewer, workflows **and** PartyKit
- [ ] Viewer Playwright suite: `fileUpload.spec.ts`, `ssrf.spec.ts`,
`webhookListener.spec.ts` all green
- [ ] Manual smoke: OpenAI `askAssistant` block streams correctly in the
embed (v4 data-stream protocol preserved)
- [ ] Manual smoke: Anthropic / Mistral / Groq blocks still execute
end-to-end
- [ ] Manual smoke: send a test email through a workspace SMTP block
(nodemailer v8)

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Baptiste Arnaud 2026-05-19 16:30:36 +02:00 committed by GitHub
parent 77fd228c96
commit 6f289f647f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
35 changed files with 458 additions and 568 deletions

View File

@ -51,8 +51,8 @@
"@effect/opentelemetry": "4.0.0-beta.38",
"@giphy/js-fetch-api": "^5.7.0",
"@giphy/react-components": "^10.1.0",
"@opentelemetry/exporter-trace-otlp-http": "^0.211.0",
"@opentelemetry/sdk-node": "^0.212.0",
"@opentelemetry/exporter-trace-otlp-http": "^0.217.0",
"@opentelemetry/sdk-node": "^0.217.0",
"@opentelemetry/sdk-trace-base": "^2.5.0",
"@orpc/client": "^1.13.9",
"@orpc/openapi": "^1.13.9",
@ -104,7 +104,7 @@
"@upstash/ratelimit": "^0.4.3",
"@use-gesture/react": "^10.3.1",
"@vercel/otel": "^2.1.1",
"ai": "^4.3.19",
"ai": "^5.0.52",
"canvas-confetti": "^1.6.0",
"codemirror": "^6.0.2",
"date-fns": "^2.30.0",
@ -125,7 +125,7 @@
"next-auth": "^5.0.0-beta.30",
"next-themes": "^0.4.6",
"nextjs-cors": "^2.1.2",
"nodemailer": "^7.0.6",
"nodemailer": "^8.0.5",
"nuqs": "^2.3.2",
"openai": "^6.9.1",
"papaparse": "^5.4.1",

View File

@ -89,7 +89,7 @@ Flowise acts as the backend for your chatbot. **It enables it to process user qu
Readwise is currently in private beta, which is why were demonstrating how to deploy it on Render.
</Warning>
To deploy Flowise, [follow our Flowise installation guide](./build-ai-chatbot-with-custom-knowledge-base#deploying-flowise-on-render-com.mdx) to set up Flowise on your local machine or a cloud platform like Render.com. Ensure you have the necessary API keys (e.g., OpenAI, Pinecone) and configure them in Flowise.
To deploy Flowise, [follow our Flowise installation guide](./build-ai-chatbot-with-custom-knowledge-base.mdx#deploying-flowise-on-rendercom) to set up Flowise on your local machine or a cloud platform like Render.com. Ensure you have the necessary API keys (e.g., OpenAI, Pinecone) and configure them in Flowise.
#### Build the Knowledge Base

View File

@ -72,7 +72,7 @@
"google-spreadsheet": "^4.1.4",
"next": "^16.1.6",
"nextjs-cors": "^2.1.2",
"nodemailer": "^7.0.6",
"nodemailer": "^8.0.5",
"openai": "^6.9.1",
"react": "^19.2.4",
"react-dom": "^19.2.4",

View File

@ -64,6 +64,11 @@
}
],
"responseVariableMapping": [
{
"id": "mapping-status",
"variableId": "var-status",
"bodyPath": "statusCode"
},
{
"id": "mapping-data",
"variableId": "var-response",
@ -86,7 +91,9 @@
"richText": [
{
"type": "p",
"children": [{ "text": "Response: {{Response}}" }]
"children": [
{ "text": "Status: {{Status}} — Response: {{Response}}" }
]
}
]
}
@ -120,6 +127,10 @@
{
"id": "var-response",
"name": "Response"
},
{
"id": "var-status",
"name": "Status"
}
],
"theme": {

View File

@ -3,6 +3,7 @@ import { createId } from "@paralleldrive/cuid2";
import test, { expect } from "@playwright/test";
import { env } from "@typebot.io/env";
import { isDefined } from "@typebot.io/lib/utils";
import { parseS3PublicBaseUrl } from "@typebot.io/lib/s3/parseS3PublicBaseUrl";
import { importTypebotInDatabase } from "@typebot.io/playwright/databaseActions";
import { parse } from "papaparse";
import { getTestAsset } from "@/test/utils/playwright";
@ -48,7 +49,7 @@ test("should work as expected", async ({ page, browser }) => {
const file = readFileSync(downloadPath as string).toString();
const { data } = parse(file);
expect(data).toHaveLength(2);
expect((data[1] as unknown[])[1]).toContain(env.S3_ENDPOINT);
expect((data[1] as unknown[])[1]).toContain(parseS3PublicBaseUrl());
const urls = (
await Promise.all(
@ -64,10 +65,19 @@ test("should work as expected", async ({ page, browser }) => {
await page2.goto(urls[0]);
await expect(page2.locator("pre")).toBeVisible();
page.getByRole("button", { name: "Delete" }).click();
await page.getByRole("button", { name: "Delete" }).click();
await page.locator('button >> text="Delete"').click();
await expect(page.locator('text="api.json"')).toBeHidden();
const page3 = await browser.newPage();
await page3.goto(urls[0]);
await expect(page3.locator("pre")).toBeHidden();
await expect
.poll(
async () => {
const res = await page.request.get(`${urls[0]}?_cb=${Date.now()}`, {
headers: { "Cache-Control": "no-cache", Pragma: "no-cache" },
});
return res.status();
},
{ timeout: 15_000, intervals: [500, 1000, 2000] },
)
.not.toBe(200);
});

View File

@ -45,7 +45,7 @@ test.describe("SSRF protection", () => {
await page.goto(`http://localhost:3000/typebots/${typebotId}/results`);
await page.click('text="See logs"');
await expect(
page.locator('text="Webhook returned an error."').first(),
page.getByText(/Security validation failed/).first(),
).toBeVisible();
});

688
bun.lock

File diff suppressed because it is too large Load Diff

View File

@ -30,7 +30,7 @@
"postinstall": "cd packages/env && bun run compile && nx db:generate prisma",
"prepare": "husky && effect-language-service patch",
"pre-commit": "nx affected -t format-and-lint,lint-repo,check-broken-links,test --parallel=4",
"dev": "nx run-many --configuration=development -t dev,watch-deps -p builder,viewer,workflows",
"dev": "nx run-many --configuration=development -t dev,watch-deps -p builder,viewer,workflows,@typebot.io/partykit",
"format-and-lint:fix": "biome check . --write --unsafe",
"lint-repo": "sherif -r unordered-dependencies -r packages-without-package-json --ignore-package @typebot.io/legacy --ignore-package bot-engine",
"lint-repo:fix": "bun run lint-repo --fix",
@ -65,6 +65,9 @@
"typescript": "^5.9.3"
},
"packageManager": "bun@1.3.9",
"overrides": {
"nodemailer": "^8.0.5"
},
"engines": {
"node": "24.x"
},

View File

@ -14,7 +14,7 @@
"@typebot.io/forge": "workspace:*",
"@typebot.io/lib": "workspace:*",
"@typebot.io/variables": "workspace:*",
"ai": "^4.3.19",
"ai": "^5.0.52",
"ky": "^1.2.4",
"@typebot.io/runtime-session-store": "workspace:*",
"zod": "^4.3.5"

View File

@ -24,7 +24,7 @@ export const parseTools = ({
if (!tool.code || !tool.name) return acc;
acc[tool.name] = {
description: tool.description,
parameters: parseParameters(tool.parameters),
inputSchema: parseParameters(tool.parameters),
execute: async (args) => {
const { output, newVariables } = await executeFunction({
sessionStore,

View File

@ -1,7 +1,7 @@
import type { LogsStore, VariableStore } from "@typebot.io/forge/types";
import { parseUnknownError } from "@typebot.io/lib/parseUnknownError";
import type { SessionStore } from "@typebot.io/runtime-session-store";
import { generateText, type LanguageModel } from "ai";
import { generateText, type LanguageModel, stepCountIs } from "ai";
import { maxSteps } from "./constants";
import { parseChatCompletionMessages } from "./parseChatCompletionMessages";
import { parseTools } from "./parseTools";
@ -50,7 +50,7 @@ export const runChatCompletion = async ({
temperature,
messages: parsedMessages,
tools: parseTools({ tools, variables, sessionStore }),
maxSteps,
stopWhen: stepCountIs(maxSteps),
headers,
});
@ -60,15 +60,15 @@ export const runChatCompletion = async ({
variables.set([{ id: mapping.variableId, value: response.text }]);
if (mapping.item === "Total tokens")
variables.set([
{ id: mapping.variableId, value: response.usage.totalTokens },
{ id: mapping.variableId, value: response.totalUsage.totalTokens },
]);
if (mapping.item === "Prompt tokens")
variables.set([
{ id: mapping.variableId, value: response.usage.promptTokens },
{ id: mapping.variableId, value: response.totalUsage.inputTokens },
]);
if (mapping.item === "Completion tokens")
variables.set([
{ id: mapping.variableId, value: response.usage.completionTokens },
{ id: mapping.variableId, value: response.totalUsage.outputTokens },
]);
});

View File

@ -4,11 +4,18 @@ import {
parseUnknownErrorSync,
} from "@typebot.io/lib/parseUnknownError";
import type { SessionStore } from "@typebot.io/runtime-session-store";
import { type LanguageModel, type StepResult, streamText, type Tool } from "ai";
import {
type LanguageModel,
type StreamTextOnFinishCallback,
stepCountIs,
streamText,
type Tool,
} from "ai";
import { maxSteps } from "./constants";
import { parseChatCompletionMessages } from "./parseChatCompletionMessages";
import { parseTools } from "./parseTools";
import type { Tools } from "./schemas";
import { toLegacyDataStream } from "./toLegacyDataStream";
import type { MessageInput } from "./types";
type Props = {
@ -24,14 +31,7 @@ type Props = {
variableId?: string;
}[]
| undefined;
onFinish?: (
response: Omit<
StepResult<Record<string, Tool>>,
"stepType" | "isContinued"
> & {
readonly steps: StepResult<Record<string, Tool>>[];
},
) => void;
onFinish?: StreamTextOnFinishCallback<Record<string, Tool>>;
sessionStore: SessionStore;
headers?: Record<string, string | undefined>;
};
@ -60,24 +60,30 @@ export const runChatCompletionStream = async ({
messages: parsedMessages,
temperature,
tools: parseTools({ tools, variables, sessionStore }),
maxSteps,
stopWhen: stepCountIs(maxSteps),
headers,
onFinish: (response) => {
responseMapping?.forEach((mapping) => {
if (!mapping.variableId) return;
if (mapping.item === "Total tokens")
variables.set([
{ id: mapping.variableId, value: response.usage.totalTokens },
{
id: mapping.variableId,
value: response.totalUsage.totalTokens,
},
]);
if (mapping.item === "Prompt tokens")
variables.set([
{ id: mapping.variableId, value: response.usage.promptTokens },
{
id: mapping.variableId,
value: response.totalUsage.inputTokens,
},
]);
if (mapping.item === "Completion tokens")
variables.set([
{
id: mapping.variableId,
value: response.usage.completionTokens,
value: response.totalUsage.outputTokens,
},
]);
});
@ -86,13 +92,13 @@ export const runChatCompletionStream = async ({
});
return {
stream: response.toDataStream({
stream: toLegacyDataStream({
stream: response.fullStream,
getErrorMessage: (err) => {
return JSON.stringify(
parseUnknownErrorSync({ err, context: "While streaming AI" }),
);
},
sendUsage: false,
}),
};
} catch (err) {

View File

@ -0,0 +1,129 @@
import type { TextStreamPart, ToolSet } from "ai";
type Props<Tools extends ToolSet> = {
stream: AsyncIterable<TextStreamPart<Tools>>;
getErrorMessage: (error: unknown) => string;
};
export const toLegacyDataStream = <Tools extends ToolSet>({
stream,
getErrorMessage,
}: Props<Tools>) =>
new ReadableStream<Uint8Array>({
async start(controller) {
const textEncoder = new TextEncoder();
let stepIndex = 0;
const enqueuePart = (type: LegacyDataStreamPartType, value: unknown) =>
controller.enqueue(
textEncoder.encode(formatLegacyDataStreamPart(type, value)),
);
try {
for await (const chunk of stream) {
switch (chunk.type) {
case "text-delta": {
enqueuePart("text", chunk.text);
break;
}
case "tool-input-start": {
enqueuePart("tool_call_streaming_start", {
toolCallId: chunk.id,
toolName: chunk.toolName,
});
break;
}
case "tool-input-delta": {
enqueuePart("tool_call_delta", {
toolCallId: chunk.id,
argsTextDelta: chunk.delta,
});
break;
}
case "tool-call": {
enqueuePart("tool_call", {
toolCallId: chunk.toolCallId,
toolName: chunk.toolName,
args: chunk.input,
});
break;
}
case "tool-result": {
enqueuePart("tool_result", {
toolCallId: chunk.toolCallId,
result: chunk.output,
});
break;
}
case "tool-error": {
enqueuePart("error", getErrorMessage(chunk.error));
break;
}
case "file": {
enqueuePart("file", {
data: chunk.file.base64,
mimeType: chunk.file.mediaType,
});
break;
}
case "start-step": {
stepIndex += 1;
enqueuePart("start_step", { messageId: `step-${stepIndex}` });
break;
}
case "finish-step": {
enqueuePart("finish_step", {
finishReason: chunk.finishReason,
isContinued: false,
});
break;
}
case "finish": {
enqueuePart("finish_message", {
finishReason: chunk.finishReason,
});
break;
}
case "error": {
enqueuePart("error", getErrorMessage(chunk.error));
break;
}
}
}
} catch (error) {
enqueuePart("error", getErrorMessage(error));
} finally {
controller.close();
}
},
});
type LegacyDataStreamPartType =
| "text"
| "error"
| "tool_call"
| "tool_result"
| "tool_call_streaming_start"
| "tool_call_delta"
| "finish_message"
| "finish_step"
| "start_step"
| "file";
const legacyDataStreamPrefixes = {
text: "0",
error: "3",
tool_call: "9",
tool_result: "a",
tool_call_streaming_start: "b",
tool_call_delta: "c",
finish_message: "d",
finish_step: "e",
start_step: "f",
file: "k",
} satisfies Record<LegacyDataStreamPartType, string>;
const formatLegacyDataStreamPart = (
type: LegacyDataStreamPartType,
value: unknown,
) => `${legacyDataStreamPrefixes[type]}:${JSON.stringify(value) ?? "null"}\n`;

View File

@ -52,7 +52,7 @@
"ky": "^1.2.4",
"libphonenumber-js": "1.10.37",
"node-html-parser": "6.1.5",
"nodemailer": "^7.0.6",
"nodemailer": "^8.0.5",
"openai": "^6.9.1",
"qs": "^6.11.2",
"stripe": "17.1.0",
@ -63,7 +63,7 @@
"@typebot.io/forge": "workspace:*",
"@typebot.io/forge-repository": "workspace:*",
"@types/qs": "^6.9.7",
"@types/nodemailer": "^7.0.1",
"@types/nodemailer": "^8.0.0",
"@types/bun": "^1.3.9",
"dotenv-cli": "^8.0.0"
}

View File

@ -12,7 +12,6 @@
"./package.json": "./package.json"
},
"dependencies": {
"ai": "3.3.15",
"openai": "4.81.0"
},
"scripts": {}

View File

@ -1 +1,59 @@
export { OpenAIStream, StreamingTextResponse } from "ai";
type OpenAIChatCompletionChunk = {
choices?: {
delta?: {
content?: string | null;
};
}[];
};
export const OpenAIStream = (
response: AsyncIterable<OpenAIChatCompletionChunk>,
): ReadableStream<Uint8Array> =>
new ReadableStream<Uint8Array>({
async start(controller) {
const textEncoder = new TextEncoder();
try {
for await (const chunk of response) {
const content = chunk.choices?.[0]?.delta?.content;
if (!content) continue;
controller.enqueue(
textEncoder.encode(formatDataStreamPart("text", content)),
);
}
} catch (error) {
controller.enqueue(
textEncoder.encode(
formatDataStreamPart("error", getErrorMessage(error)),
),
);
} finally {
controller.close();
}
},
});
export class StreamingTextResponse extends Response {
constructor(stream: BodyInit, init?: ResponseInit) {
const headers = new Headers(init?.headers);
if (!headers.has("Content-Type"))
headers.set("Content-Type", "text/plain; charset=utf-8");
super(stream, {
...init,
status: init?.status ?? 200,
headers,
});
}
}
const formatDataStreamPart = (type: "text" | "error", value: string) =>
`${getDataStreamPrefix(type)}:${JSON.stringify(value) ?? '""'}\n`;
const getDataStreamPrefix = (type: "text" | "error") =>
type === "text" ? "0" : "3";
const getErrorMessage = (error: unknown) => {
if (error instanceof Error) return error.message;
return String(error);
};

View File

@ -24,7 +24,7 @@
"@typebot.io/prisma": "workspace:*",
"@typebot.io/env": "workspace:*",
"effect": "4.0.0-beta.38",
"nodemailer": "^7.0.6",
"nodemailer": "^8.0.5",
"react-email": "^4.2.8",
"@react-email/render": "^1.2.1",
"@typebot.io/lib": "workspace:*",
@ -35,6 +35,6 @@
"@react-email/preview-server": "^4.2.8",
"dotenv-cli": "^8.0.0",
"@types/react": "^19.2.14",
"@types/nodemailer": "^7.0.1"
"@types/nodemailer": "^8.0.0"
}
}

View File

@ -25,7 +25,7 @@
"@typebot.io/ai": "workspace:*",
"@typebot.io/forge": "workspace:*",
"@typebot.io/lib": "workspace:*",
"@ai-sdk/anthropic": "^1.2.12",
"@ai-sdk/anthropic": "^2.0.79",
"zod": "^4.3.5"
},
"devDependencies": {

View File

@ -22,7 +22,7 @@
"./package.json": "./package.json"
},
"dependencies": {
"@ai-sdk/deepseek": "^0.2.16",
"@ai-sdk/deepseek": "^1.0.40",
"@typebot.io/ai": "workspace:*",
"@typebot.io/forge": "workspace:*"
},

View File

@ -25,7 +25,7 @@
"@ai-sdk/ui-utils": "^1.2.11",
"@typebot.io/forge": "workspace:*",
"@typebot.io/lib": "workspace:*",
"dify-ai-provider": "^0.1.6",
"dify-ai-provider": "^1.1.0",
"ky": "^1.2.4",
"@typebot.io/ai": "workspace:*"
},

View File

@ -25,11 +25,11 @@
"@googleapis/gmail": "^14.0.1",
"google-auth-library": "^10.1.0",
"@typebot.io/lib": "workspace:*",
"nodemailer": "^7.0.6",
"nodemailer": "^8.0.5",
"ky": "^1.2.4"
},
"devDependencies": {
"@types/nodemailer": "^7.0.1",
"@types/nodemailer": "^8.0.0",
"@types/react": "^19.2.14"
}
}

View File

@ -25,7 +25,7 @@
"@typebot.io/forge": "workspace:*",
"@typebot.io/ai": "workspace:*",
"@typebot.io/lib": "workspace:*",
"@ai-sdk/groq": "^1.2.9",
"@ai-sdk/groq": "^2.0.40",
"@types/react": "^19.2.14"
},
"dependencies": {

View File

@ -27,7 +27,7 @@
"@types/react": "^19.2.14"
},
"dependencies": {
"@ai-sdk/mistral": "^1.2.8",
"@ai-sdk/mistral": "^2.0.33",
"@typebot.io/ai": "workspace:*"
}
}

View File

@ -26,7 +26,7 @@
"@typebot.io/ai": "workspace:*",
"@typebot.io/lib": "workspace:*",
"ky": "^1.2.4",
"@openrouter/ai-sdk-provider": "^0.1.0",
"@openrouter/ai-sdk-provider": "^1.5.4",
"@types/react": "^19.2.14"
}
}

View File

@ -27,7 +27,7 @@
"./package.json": "./package.json"
},
"dependencies": {
"@ai-sdk/openai": "^1.3.24",
"@ai-sdk/openai": "^2.0.106",
"@sentry/nextjs": "^10.43.0",
"@typebot.io/ai": "workspace:*",
"@ai-sdk/ui-utils": "^1.2.11",

View File

@ -18,7 +18,6 @@ export const generateVariables = createAction({
getModel: ({ credentials, model }) =>
createOpenAI({
apiKey: credentials.apiKey,
compatibility: "strict",
})(model),
},
turnableInto: [

View File

@ -1,3 +1,4 @@
import { formatDataStreamPart, processDataStream } from "@ai-sdk/ui-utils";
import * as Sentry from "@sentry/nextjs";
import { createActionHandler, createFetcherHandler } from "@typebot.io/forge";
import type {
@ -10,7 +11,6 @@ import { safeStringify } from "@typebot.io/lib/safeStringify";
import { isDefined, isEmpty, isNotEmpty } from "@typebot.io/lib/utils";
import type { SessionStore } from "@typebot.io/runtime-session-store";
import { executeFunction } from "@typebot.io/variables/executeFunction";
import { formatDataStreamPart, processDataStream } from "ai";
import type { ClientOptions } from "openai";
import OpenAI from "openai";
import {

View File

@ -1,3 +1,4 @@
import { formatDataStreamPart, processDataStream } from "@ai-sdk/ui-utils";
import { createActionHandler } from "@typebot.io/forge";
import type {
AsyncVariableStore,
@ -9,7 +10,6 @@ import { safeStringify } from "@typebot.io/lib/safeStringify";
import { isDefined, isEmpty, isNotEmpty } from "@typebot.io/lib/utils";
import type { SessionStore } from "@typebot.io/runtime-session-store";
import { executeFunction } from "@typebot.io/variables/executeFunction";
import { formatDataStreamPart, processDataStream } from "ai";
import type { ClientOptions } from "openai";
import OpenAI from "openai";
import type { ResponseStreamEvent } from "openai/resources/responses/responses";

View File

@ -24,7 +24,6 @@ export const createChatCompletionHandler = createActionHandler(
model: createOpenAI({
baseURL: baseUrl ?? options.baseUrl,
apiKey,
compatibility: "strict",
})(modelName),
variables,
messages: options.messages,
@ -71,7 +70,6 @@ export const createChatCompletionHandler = createActionHandler(
model: createOpenAI({
baseURL: baseUrl ?? options.baseUrl,
apiKey,
compatibility: "strict",
})(modelName),
variables,
messages: options.messages,

View File

@ -14,7 +14,6 @@ export const generateVariablesHandler = createActionHandler(generateVariables, {
model: createOpenAI({
apiKey: credentials.apiKey,
baseURL: credentials.baseUrl ?? options.baseUrl,
compatibility: "strict",
})(options.model),
prompt: options.prompt,
variablesToExtract: options.variablesToExtract,

View File

@ -22,7 +22,7 @@
"./package.json": "./package.json"
},
"dependencies": {
"@ai-sdk/perplexity": "^1.1.9",
"@ai-sdk/perplexity": "^2.0.30",
"@typebot.io/ai": "workspace:*",
"@typebot.io/forge": "workspace:*",
"@typebot.io/lib": "workspace:*"

View File

@ -24,7 +24,7 @@
"devDependencies": {
"@typebot.io/forge": "workspace:*",
"@typebot.io/ai": "workspace:*",
"@ai-sdk/togetherai": "^0.2.16",
"@ai-sdk/togetherai": "^1.0.42",
"@types/react": "^19.2.14"
}
}

View File

@ -18,7 +18,7 @@
"effect": "4.0.0-beta.38",
"ky": "^1.2.4",
"ioredis": "^5.4.1",
"nodemailer": "^7.0.6",
"nodemailer": "^8.0.5",
"minio": "7.1.3",
"validator": "^13.12.0",
"@paralleldrive/cuid2": "^2.2.1",

View File

@ -49,7 +49,7 @@
"./package.json": "./package.json"
},
"dependencies": {
"@ai-sdk/openai": "^1.3.24",
"@ai-sdk/openai": "^2.0.106",
"ky": "^1.2.4",
"@clack/prompts": "^0.11.0",
"@paralleldrive/cuid2": "^2.2.1",
@ -71,7 +71,7 @@
"@typebot.io/blocks-core": "workspace:*",
"@typebot.io/groups": "workspace:*",
"@typebot.io/rich-text": "workspace:*",
"ai": "^4.3.19",
"ai": "^5.0.52",
"p-limit": "^7.2.0",
"zod": "^4.3.5"
},

View File

@ -16,7 +16,7 @@
"@opentelemetry/api": "^1.9.0",
"@opentelemetry/api-logs": "^0.211.0",
"@opentelemetry/exporter-logs-otlp-http": "^0.211.0",
"@opentelemetry/exporter-trace-otlp-http": "^0.211.0",
"@opentelemetry/exporter-trace-otlp-http": "^0.217.0",
"@opentelemetry/resources": "^2.5.0",
"@opentelemetry/sdk-logs": "^0.211.0",
"@opentelemetry/sdk-trace-base": "^2.5.0",