trigger.dev icon indicating copy to clipboard operation
trigger.dev copied to clipboard

feat(react-hooks): add TriggerChatTransport for AI SDK useChat

Open jakevollkommer opened this issue 2 months ago • 2 comments

Closes #2634

✅ Checklist

  • [x] I have followed every step in the contributing guide
  • [x] The PR title follows the convention.
  • [x] I ran and tested the code works

Summary

Adds a custom transport implementation for AI SDK's useChat hook that integrates with Trigger.dev background tasks. This enables long-running AI conversations by triggering tasks, subscribing to realtime run updates via Electric SQL, and streaming AI responses via Server-Sent Events (SSE).

Changes

  • New Hook: useTriggerChat - A drop-in replacement for AI SDK's useChat that works with Trigger.dev tasks
  • Transport Class: TriggerChatTransport - Custom transport implementation following AI SDK's transport pattern
  • Dependencies: Added ai (^5.0.82), @ai-sdk/react (^2.0.14), and eventsource-parser (^3.0.0)

Technical Details

Architecture

Developer Requirements

Important: Developers must create their own server action to trigger tasks. Since useTriggerChat is a client-side hook, it cannot directly call tasks.trigger() (which requires server-side execution). The triggerTask option expects a server action that:

  1. Accepts the task identifier and payload
  2. Calls tasks.trigger() on the server
  3. Returns { success: true, runId, publicAccessToken }

Error Handling

  • Gracefully handles stream disconnections and abort signals
  • Warns on unparseable SSE chunks without breaking the stream
  • Only closes controller when run finishes (not when individual streams end)

Testing

Manually tested with a local project using pnpm patch to verify:

  • ✅ Task triggering and run creation
  • ✅ Realtime run status updates
  • ✅ SSE streaming of AI responses
  • ✅ Multiple concurrent streams
  • ✅ Graceful handling of stream completion
  • ✅ TypeScript compilation

Usage Example

1. Define your Trigger.dev task (e.g. src/trigger/chat.ts):

import { metadata, task } from "@trigger.dev/sdk/v3";
import { streamText } from "ai";
import { openai } from "@ai-sdk/openai";

export const chatTask = task({
  id: "chat",
  run: async ({ messages }: { messages: Array<{ role: string; content: string }> }) => {
    const result = streamText({
      model: openai("gpt-5"),
      messages,
    });

    // CRITICAL: Stream the result to the client using metadata.stream()
    // The stream key MUST match the streamKey option in useTriggerChat (default: "chat")
    await metadata.stream("chat", result.toUIMessageStream());

    const text = await result.text;
    return { text };
  },
});

2. Create a server action (e.g. src/actions.ts):

"use server";

import { tasks } from "@trigger.dev/sdk/v3";

export async function triggerChatTask(task: string, payload: unknown) {
  const handle = await tasks.trigger(task, payload);
  return {
    success: true,
    runId: handle.id,
    publicAccessToken: handle.publicAccessToken,
  };
}

3. Use the hook in your component (e.g. src/components/Chat.tsx):

"use client";

import { useTriggerChat } from "@trigger.dev/react-hooks";
import { chatTask } from "../trigger/chat";
import { triggerChatTask } from "../actions";

export function Chat() {
  const { messages, input, handleInputChange, handleSubmit } = useTriggerChat({
    triggerTask: triggerChatTask,
  });

  return (
    <form onSubmit={handleSubmit}>
      <div>
        {messages.map((msg) => (
          <div key={msg.id}>
            <strong>{msg.role}:</strong> {msg.content}
          </div>
        ))}
      </div>
      <input value={input} onChange={handleInputChange} />
      <button type="submit">Send</button>
    </form>
  );
}

Changelog

Added useTriggerChat hook to @trigger.dev/react-hooks that provides AI SDK useChat integration with Trigger.dev background tasks. Enables long-running AI conversations with realtime streaming via custom transport implementation.

New exports:

  • useTriggerChat - Hook for AI chat integration
  • TriggerChatTransport - Custom transport class
  • TriggerChatTransportOptions - Transport configuration type
  • TriggerChatTaskPayload - Task payload type

New dependencies:

  • ai@^5.0.82
  • @ai-sdk/react@^2.0.14
  • eventsource-parser@^3.0.0

Resources


Screenshots

N/A - This is a developer-facing hook with no UI

💯

jakevollkommer avatar Oct 29 '25 20:10 jakevollkommer

🦋 Changeset detected

Latest commit: b94f4f2f4f5f564f4de2a69dd116463f01ed348c

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 23 packages
Name Type
@trigger.dev/react-hooks Minor
d3-chat Patch
references-d3-openai-agents Patch
references-nextjs-realtime Patch
@trigger.dev/build Minor
@trigger.dev/core Minor
@trigger.dev/python Minor
@trigger.dev/redis-worker Minor
@trigger.dev/rsc Minor
@trigger.dev/schema-to-json Minor
@trigger.dev/sdk Minor
@trigger.dev/database Minor
@trigger.dev/otlp-importer Minor
trigger.dev Minor
@internal/cache Patch
@internal/clickhouse Patch
@internal/redis Patch
@internal/replication Patch
@internal/run-engine Patch
@internal/schedule-engine Patch
@internal/testcontainers Patch
@internal/tracing Patch
@internal/zod-worker Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

changeset-bot[bot] avatar Oct 29 '25 20:10 changeset-bot[bot]

Walkthrough

Adds a new TriggerChatTransport class and accompanying useTriggerChat React hook that provide Trigger.dev–backed streaming chat integration for the AI SDK. Introduces types, helpers for SSE/stream subscription and metadata parsing, reconnect logic, access-token handling, and runtime abort/cleanup behavior. Exports the new hook from the package index, updates packages/react-hooks/package.json to declare four optional peer dependencies (@ai-sdk/react, @electric-sql/client, ai, eventsource-parser), and adds a changelog entry for a minor release. No existing public APIs were removed.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

  • Areas to focus on:
    • packages/react-hooks/src/hooks/useTriggerChat.ts (TriggerChatTransport lifecycle, sendMessages/reconnectToStream behavior, SSE parsing, stream enqueueing, abort and cleanup)
    • subscribeToDataStreams / streamDataFromTrigger and metadata parsing correctness and error handling
    • Access token resolution (static vs function) and caching logic
    • package.json peerDependencies and peerDependenciesMeta entries for optionality
    • packages/react-hooks/src/index.ts export addition
    • .changeset entry for correctness and release metadata consistency

Pre-merge checks and finishing touches

✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed Title clearly describes the main feature: adding TriggerChatTransport for AI SDK useChat integration, directly matching the primary code changes.
Description check ✅ Passed Description is comprehensive and follows the template with completed checklist, testing details, detailed changelog, and technical documentation.
Linked Issues check ✅ Passed All coding requirements from issue #2634 are met: custom transport implemented, task triggering enabled, metadata stream subscription integrated, and realtime features leveraged.
Out of Scope Changes check ✅ Passed All changes are directly aligned with issue #2634 objectives: new hook, transport class, optional peer dependencies, and exports supporting AI SDK integration.
✨ Finishing touches
  • [ ] 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • [ ] Create PR with unit tests
  • [ ] Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

coderabbitai[bot] avatar Oct 29 '25 20:10 coderabbitai[bot]