Skip to content

Commit b3cb0cc

Browse files
fix(useTriggerChat): make AI SDK dependencies optional peer dependencies
1 parent ba97cb0 commit b3cb0cc

File tree

3 files changed

+77
-91
lines changed

3 files changed

+77
-91
lines changed

packages/react-hooks/package.json

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,7 @@
3737
"check-exports": "attw --pack ."
3838
},
3939
"dependencies": {
40-
"@ai-sdk/react": "^2.0.14",
41-
"@electric-sql/client": "1.0.14",
4240
"@trigger.dev/core": "workspace:^4.0.5",
43-
"ai": "^5.0.82",
44-
"eventsource-parser": "^3.0.0",
4541
"swr": "^2.2.5"
4642
},
4743
"devDependencies": {
@@ -54,7 +50,25 @@
5450
},
5551
"peerDependencies": {
5652
"react": "^18.0 || ^19.0 || ^19.0.0-rc",
57-
"react-dom": "^18.0 || ^19.0 || ^19.0.0-rc"
53+
"react-dom": "^18.0 || ^19.0 || ^19.0.0-rc",
54+
"@ai-sdk/react": "^2.0.0",
55+
"@electric-sql/client": "^1.0.0",
56+
"ai": "^5.0.0",
57+
"eventsource-parser": "^3.0.0"
58+
},
59+
"peerDependenciesMeta": {
60+
"@ai-sdk/react": {
61+
"optional": true
62+
},
63+
"@electric-sql/client": {
64+
"optional": true
65+
},
66+
"ai": {
67+
"optional": true
68+
},
69+
"eventsource-parser": {
70+
"optional": true
71+
}
5872
},
5973
"engines": {
6074
"node": ">=18.20.0"

packages/react-hooks/src/hooks/useTriggerChat.ts

Lines changed: 54 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -4,25 +4,14 @@ import { ShapeStream } from "@electric-sql/client";
44
import { EventSourceParserStream } from "eventsource-parser/stream";
55

66
import { useChat, type UseChatHelpers } from "@ai-sdk/react";
7-
import type {
8-
UIMessage,
9-
UIMessageChunk,
10-
ChatRequestOptions,
11-
ChatInit,
12-
} from "ai";
13-
import type {
14-
AnyTask,
15-
TaskIdentifier,
16-
AnyRealtimeRun,
17-
} from "@trigger.dev/core/v3";
7+
import type { UIMessage, UIMessageChunk, ChatRequestOptions, ChatInit } from "ai";
8+
import type { AnyTask, TaskIdentifier, AnyRealtimeRun } from "@trigger.dev/core/v3";
189

1910
const DEFAULT_TASK = "chat";
2011
const DEFAULT_STREAM_KEY = "chat";
2112
const DEFAULT_BASE_URL = "https://api.trigger.dev";
2213

23-
export interface TriggerChatTaskPayload<
24-
UI_MESSAGE extends UIMessage = UIMessage,
25-
> {
14+
export interface TriggerChatTaskPayload<UI_MESSAGE extends UIMessage = UIMessage> {
2615
chatId?: string;
2716
messageId?: string;
2817
messages: UI_MESSAGE[];
@@ -92,7 +81,7 @@ export interface TriggerChatTransportOptions<
9281
*/
9382
triggerTask: (
9483
task: TaskIdentifier<AnyTask>,
95-
payload: TriggerChatTaskPayload,
84+
payload: TriggerChatTaskPayload
9685
) => Promise<{
9786
success: boolean;
9887
runId?: string;
@@ -159,9 +148,7 @@ type ParsedMetadata = {
159148
*/
160149
export class TriggerChatTransport {
161150
private readonly task: TaskIdentifier<AnyTask>;
162-
private readonly triggerTask: NonNullable<
163-
TriggerChatTransportOptions["triggerTask"]
164-
>;
151+
private readonly triggerTask: NonNullable<TriggerChatTransportOptions["triggerTask"]>;
165152
private readonly accessToken?: string | (() => string | Promise<string>);
166153
private readonly streamKey: string;
167154
private readonly baseURL: string;
@@ -183,7 +170,7 @@ export class TriggerChatTransport {
183170
options: {
184171
abortSignal: AbortSignal | undefined;
185172
} & ChatRequestOptions &
186-
TriggerChatTaskPayload,
173+
TriggerChatTaskPayload
187174
): Promise<ReadableStream<UIMessageChunk>> {
188175
const { abortSignal, ...payloadOptions } = options;
189176

@@ -209,7 +196,7 @@ export class TriggerChatTransport {
209196
}
210197

211198
async reconnectToStream(
212-
options: { chatId: string } & ChatRequestOptions,
199+
options: { chatId: string } & ChatRequestOptions
213200
): Promise<ReadableStream<UIMessageChunk> | null> {
214201
const runId = this.activeRuns.get(options.chatId);
215202

@@ -235,7 +222,7 @@ export class TriggerChatTransport {
235222

236223
private async subscribeToRun(
237224
runId: string,
238-
abortSignal: AbortSignal | undefined,
225+
abortSignal: AbortSignal | undefined
239226
): Promise<ReadableStream<UIMessageChunk>> {
240227
const accessToken = await this.resolveAccessToken(runId);
241228
const streamKey = this.streamKey;
@@ -307,7 +294,7 @@ export class TriggerChatTransport {
307294
if (abortSignal) {
308295
abortSignal.removeEventListener("abort", handleAbort);
309296
}
310-
},
297+
}
311298
);
312299
} catch (error) {
313300
cleanup();
@@ -325,7 +312,7 @@ export class TriggerChatTransport {
325312

326313
if (!this.accessToken) {
327314
throw new Error(
328-
"No access token available. Provide accessToken option or ensure tasks.trigger() returns publicAccessToken",
315+
"No access token available. Provide accessToken option or ensure tasks.trigger() returns publicAccessToken"
329316
);
330317
}
331318

@@ -342,7 +329,7 @@ export class TriggerChatTransport {
342329
* Handles both string (JSON) and object formats
343330
*/
344331
function parseMetadata(
345-
metadata: Record<string, unknown> | string | undefined,
332+
metadata: Record<string, unknown> | string | undefined
346333
): ParsedMetadata | undefined {
347334
if (!metadata) return undefined;
348335

@@ -387,9 +374,7 @@ function subscribeToDataStreams(params: {
387374
} = params;
388375

389376
if (!metadata?.$$streams || !Array.isArray(metadata.$$streams)) {
390-
console.warn(
391-
"Unable to subscribe to streams: metadata.$$streams does not contain an array",
392-
);
377+
console.warn("Unable to subscribe to streams: metadata.$$streams does not contain an array");
393378
return;
394379
}
395380

@@ -422,14 +407,7 @@ async function streamDataFromTrigger(params: {
422407
runAbortController: AbortController;
423408
controller: ReadableStreamDefaultController<UIMessageChunk>;
424409
}) {
425-
const {
426-
streamKey,
427-
runId,
428-
baseURL,
429-
accessToken,
430-
runAbortController,
431-
controller,
432-
} = params;
410+
const { streamKey, runId, baseURL, accessToken, runAbortController, controller } = params;
433411

434412
try {
435413
const streamUrl = `${baseURL}/realtime/v1/streams/${runId}/${streamKey}`;
@@ -479,8 +457,7 @@ async function streamDataFromTrigger(params: {
479457
reader.releaseLock();
480458
}
481459
} catch (error) {
482-
const shouldIgnoreError =
483-
error instanceof Error && error.name === "AbortError";
460+
const shouldIgnoreError = error instanceof Error && error.name === "AbortError";
484461

485462
if (!shouldIgnoreError) {
486463
throw error;
@@ -572,9 +549,46 @@ type UseTriggerChatOptions = {
572549
* }
573550
* ```
574551
*/
575-
export function useTriggerChat(
576-
options: UseTriggerChatOptions,
577-
): UseChatHelpers<UIMessage> {
552+
export function useTriggerChat(options: UseTriggerChatOptions): UseChatHelpers<UIMessage> {
553+
// Check for required peer dependencies at runtime
554+
try {
555+
require.resolve("@ai-sdk/react");
556+
require.resolve("ai");
557+
require.resolve("@electric-sql/client");
558+
require.resolve("eventsource-parser");
559+
} catch (e) {
560+
const missing: string[] = [];
561+
try {
562+
require.resolve("@ai-sdk/react");
563+
} catch {
564+
missing.push("@ai-sdk/react");
565+
}
566+
try {
567+
require.resolve("ai");
568+
} catch {
569+
missing.push("ai");
570+
}
571+
try {
572+
require.resolve("@electric-sql/client");
573+
} catch {
574+
missing.push("@electric-sql/client");
575+
}
576+
try {
577+
require.resolve("eventsource-parser");
578+
} catch {
579+
missing.push("eventsource-parser");
580+
}
581+
582+
throw new Error(
583+
`useTriggerChat requires the following packages:\n${missing
584+
.map((pkg) => ` - ${pkg}`)
585+
.join("\n")}\n\n` +
586+
`Install them with:\n npm install ${missing.join(" ")}\n or\n pnpm add ${missing.join(
587+
" "
588+
)}`
589+
);
590+
}
591+
578592
const { transportOptions, ...chatOptions } = options;
579593

580594
return useChat({

pnpm-lock.yaml

Lines changed: 4 additions & 46 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)