Skip to content

Pr 3173 fix#3338

Closed
deepshekhardas wants to merge 77 commits intotriggerdotdev:mainfrom
deepshekhardas:pr-3173-fix
Closed

Pr 3173 fix#3338
deepshekhardas wants to merge 77 commits intotriggerdotdev:mainfrom
deepshekhardas:pr-3173-fix

Conversation

@deepshekhardas
Copy link
Copy Markdown

Closes #

✅ Checklist

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

Testing

[Describe the steps you took to test this change]


Changelog

[Short description of what has changed]


Screenshots

[Screenshots]

💯

cursoragent and others added 30 commits April 1, 2026 14:52
New package that provides a custom AI SDK ChatTransport implementation
bridging Vercel AI SDK's useChat hook with Trigger.dev's durable task
execution and realtime streams.

Key exports:
- TriggerChatTransport class implementing ChatTransport<UIMessage>
- createChatTransport() factory function
- ChatTaskPayload type for task-side typing
- TriggerChatTransportOptions type

The transport triggers a Trigger.dev task with chat messages as payload,
then subscribes to the task's realtime stream to receive UIMessageChunk
data, which useChat processes natively.

Co-authored-by: Eric Allam <eric@trigger.dev>
Tests cover:
- Constructor with required and optional options
- sendMessages triggering task and returning UIMessageChunk stream
- Correct payload structure sent to trigger API
- Custom streamKey in stream URL
- Extra headers propagation
- reconnectToStream with existing and non-existing sessions
- createChatTransport factory function
- Error handling for API failures
- regenerate-message trigger type

Co-authored-by: Eric Allam <eric@trigger.dev>
- Cache ApiClient instance instead of creating per-call
- Add streamTimeoutSeconds option for customizable stream timeout
- Clean up subscribeToStream method (remove unused variable)
- Improve JSDoc with backend task example
- Minor code cleanup

Co-authored-by: Eric Allam <eric@trigger.dev>
Adds 3 additional test cases:
- Abort signal gracefully closes the stream
- Multiple independent chat sessions tracked correctly
- ChatRequestOptions.body is merged into task payload

Co-authored-by: Eric Allam <eric@trigger.dev>
Co-authored-by: Eric Allam <eric@trigger.dev>
ChatSessionState is an implementation detail of the transport's
session tracking. Users don't need to access it since the sessions
map is private.

Co-authored-by: Eric Allam <eric@trigger.dev>
The accessToken option now accepts either a string or a function
returning a string. This enables dynamic token refresh patterns:

  new TriggerChatTransport({
    taskId: 'my-task',
    accessToken: () => getLatestToken(),
  })

The function is called on each sendMessages() call, allowing fresh
tokens to be used for each task trigger.

Co-authored-by: Eric Allam <eric@trigger.dev>
Use the already-resolved token when creating ApiClient instead of
calling resolveAccessToken() again through getApiClient().

Co-authored-by: Eric Allam <eric@trigger.dev>
Two new subpath exports:

@trigger.dev/sdk/chat (frontend, browser-safe):
- TriggerChatTransport — ChatTransport implementation for useChat
- createChatTransport() — factory function
- TriggerChatTransportOptions type

@trigger.dev/sdk/ai (backend, adds to existing ai.tool/ai.currentToolOptions):
- chatTask() — pre-typed task wrapper with auto-pipe
- pipeChat() — pipe StreamTextResult to realtime stream
- CHAT_STREAM_KEY constant
- ChatTaskPayload type
- ChatTaskOptions type
- PipeChatOptions type

Co-authored-by: Eric Allam <eric@trigger.dev>
Move and adapt tests from packages/ai to packages/trigger-sdk.
- Import from ./chat.js instead of ./transport.js
- Use 'task' option instead of 'taskId'
- All 17 tests passing

Co-authored-by: Eric Allam <eric@trigger.dev>
All functionality now lives in:
- @trigger.dev/sdk/chat (frontend transport)
- @trigger.dev/sdk/ai (backend chatTask, pipeChat)

Co-authored-by: Eric Allam <eric@trigger.dev>
Co-authored-by: Eric Allam <eric@trigger.dev>
1. Add null/object guard before enqueuing UIMessageChunk from SSE stream
   to handle heartbeat or malformed events safely
2. Use incrementing counter instead of Date.now() in test message
   factories to avoid duplicate IDs
3. Add test covering publicAccessToken from trigger response being used
   for stream subscription auth

Co-authored-by: Eric Allam <eric@trigger.dev>
Comprehensive guide covering:
- Quick start with chatTask + TriggerChatTransport
- Backend patterns: simple (return streamText), complex (pipeChat),
  and manual (task + ChatTaskPayload)
- Frontend options: dynamic tokens, extra data, self-hosting
- ChatTaskPayload reference
- Added to Writing tasks navigation near Streams

Co-authored-by: Eric Allam <eric@trigger.dev>
Minimal example showcasing the new chatTask + TriggerChatTransport APIs:
- Backend: chatTask with streamText auto-pipe (src/trigger/chat.ts)
- Frontend: TriggerChatTransport with useChat (src/components/chat.tsx)
- Token generation via auth.createTriggerPublicToken (src/app/page.tsx)
- Tailwind v4 styling

Co-authored-by: Eric Allam <eric@trigger.dev>
…delMessages

@ai-sdk/openai v3 and @ai-sdk/react v3 are needed for ai v6 compatibility.
convertToModelMessages is async in newer AI SDK versions.

Co-authored-by: Eric Allam <eric@trigger.dev>
ericallam and others added 25 commits April 1, 2026 14:52
Replace triggerAndWait with triggerAndSubscribe in ai.tool to fix:
- Parallel tool calls (no more preventMultipleWaits errors)
- Stop signal while suspended (parent stays alive, child gets cancelled)

New task.triggerAndSubscribe() method: trigger + subscribeToRun in a
single span, with abort signal support and cancelOnAbort option.

Convert deepResearch to a schemaTask + ai.tool in the reference app.

refs TRI-7986
…at.defer improvements

- chat.inject(): queue model messages from background work for injection
  at the next prepareStep boundary or before the next turn's run()
- Deferred work from onTurnComplete no longer blocks waiting for next message
- Background queue persists across turns (not reset) so deferred work from
  onTurnComplete can inject into the next turn
- Reference app: self-review pattern using generateObject + chat.inject()
- Hide transient data-turn-status and data-background-context-injected parts in UI
… ai.tool

- Assert toolFromTask return as AI SDK ToolSet-compatible; import ToolSet from ai
- Add changesets for @trigger.dev/sdk
- ai-chat reference: chat-tools module, registry language model helper, streamText cleanup
- Prisma migration removing user tool demo; demo docs and next config tweaks
- Pass TaskRunContext through chat lifecycle events, CompactedEvent, and
  ChatTaskRunPayload; use ctx.run.id for chat access tokens
- Export TaskRunContext from @trigger.dev/sdk
- ai-chat reference: executeCode via E2B, code-sandbox module, warm on
  onTurnStart, dispose on token onWait and onComplete; chat.local run id
- Docs: database persistence + code sandbox pattern pages; reference and
  backend updates for ctx; chat.defer anchor; navigation
plus playground support, including playground conversations, and a new
agent list
- Upgrade streamdown from v1.4.0 to v2.5.0 with @streamdown/code plugin
- Custom Shiki theme matching the Trigger.dev VS Code dark theme colors
- Consolidate duplicated lazy StreamdownRenderer into shared component
- Patch streamdown to inline highlighted body (fixes Arc browser)
- Add streamdown storybook page for visual testing
- Handle AGENT triggerSource in TestTaskPresenter exhaustive switch
- Update Tailwind config to scan streamdown dist for utility classes
@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Apr 8, 2026

🦋 Changeset detected

Latest commit: a67ee16

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

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

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

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 8, 2026

Hi @deepshekhardas, thanks for your interest in contributing!

This project requires that pull request authors are vouched, and you are not in the list of vouched users.

This PR will be closed automatically. See https://github.com/triggerdotdev/trigger.dev/blob/main/CONTRIBUTING.md for more details.

@github-actions github-actions bot closed this Apr 8, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 8, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: a424c7f8-64b2-4365-9fda-8962f82c4eec

📥 Commits

Reviewing files that changed from the base of the PR and between def21b2 and a67ee16.

⛔ Files ignored due to path filters (38)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
  • references/ai-chat/.gitignore is excluded by !references/**
  • references/ai-chat/.nvmrc is excluded by !references/**
  • references/ai-chat/DEMO-SHORTHAND.md is excluded by !references/**
  • references/ai-chat/DEMO.md is excluded by !references/**
  • references/ai-chat/README.md is excluded by !references/**
  • references/ai-chat/next-env.d.ts is excluded by !references/**
  • references/ai-chat/next.config.ts is excluded by !references/**
  • references/ai-chat/package.json is excluded by !references/**
  • references/ai-chat/postcss.config.mjs is excluded by !references/**
  • references/ai-chat/prisma.config.ts is excluded by !references/**
  • references/ai-chat/prisma/migrations/20260305112427_init/migration.sql is excluded by !references/**
  • references/ai-chat/prisma/migrations/20260306165319_add_user_model/migration.sql is excluded by !references/**
  • references/ai-chat/prisma/migrations/20260327180000_remove_user_tool/migration.sql is excluded by !references/**
  • references/ai-chat/prisma/migrations/migration_lock.toml is excluded by !references/**
  • references/ai-chat/prisma/schema.prisma is excluded by !references/**
  • references/ai-chat/src/app/actions.ts is excluded by !references/**
  • references/ai-chat/src/app/globals.css is excluded by !references/**
  • references/ai-chat/src/app/layout.tsx is excluded by !references/**
  • references/ai-chat/src/app/page.tsx is excluded by !references/**
  • references/ai-chat/src/components/chat-app.tsx is excluded by !references/**
  • references/ai-chat/src/components/chat-sidebar.tsx is excluded by !references/**
  • references/ai-chat/src/components/chat.tsx is excluded by !references/**
  • references/ai-chat/src/lib/chat-tools.ts is excluded by !references/**
  • references/ai-chat/src/lib/code-sandbox.ts is excluded by !references/**
  • references/ai-chat/src/lib/models.ts is excluded by !references/**
  • references/ai-chat/src/lib/pr-review-helpers.ts is excluded by !references/**
  • references/ai-chat/src/lib/pr-review-sandbox.ts is excluded by !references/**
  • references/ai-chat/src/lib/pr-review-tools.ts is excluded by !references/**
  • references/ai-chat/src/lib/prisma.ts is excluded by !references/**
  • references/ai-chat/src/lib/secure-sandbox.ts is excluded by !references/**
  • references/ai-chat/src/trigger/chat-client-test.ts is excluded by !references/**
  • references/ai-chat/src/trigger/chat.ts is excluded by !references/**
  • references/ai-chat/src/trigger/pr-review.ts is excluded by !references/**
  • references/ai-chat/trigger.config.ts is excluded by !references/**
  • references/ai-chat/tsconfig.json is excluded by !references/**
  • references/hello-world/src/trigger/chatAgent.ts is excluded by !references/**
  • references/hello-world/src/trigger/triggerAndSubscribe.ts is excluded by !references/**
📒 Files selected for processing (109)
  • .changeset/ai-chat-sandbox-and-ctx.md
  • .changeset/ai-sdk-chat-transport.md
  • .changeset/ai-sdk-usechat-transport.md
  • .changeset/ai-tool-execute-helper.md
  • .changeset/ai-tool-toolset-typing.md
  • .changeset/chat-run-pat-renewal.md
  • .changeset/dry-sloths-divide.md
  • .claude/rules/package-installation.md
  • .server-changes/streamdown-v2-upgrade.md
  • CLAUDE.md
  • apps/webapp/app/components/BulkActionFilterSummary.tsx
  • apps/webapp/app/components/code/AIQueryInput.tsx
  • apps/webapp/app/components/code/StreamdownRenderer.tsx
  • apps/webapp/app/components/code/shikiTheme.ts
  • apps/webapp/app/components/navigation/SideMenu.tsx
  • apps/webapp/app/components/runs/v3/PromptSpanDetails.tsx
  • apps/webapp/app/components/runs/v3/RunFilters.tsx
  • apps/webapp/app/components/runs/v3/TaskRunsTable.tsx
  • apps/webapp/app/components/runs/v3/TaskTriggerSource.tsx
  • apps/webapp/app/components/runs/v3/ai/AIChatMessages.tsx
  • apps/webapp/app/components/runs/v3/ai/AISpanDetails.tsx
  • apps/webapp/app/components/runs/v3/ai/types.ts
  • apps/webapp/app/presenters/RunFilters.server.ts
  • apps/webapp/app/presenters/v3/AgentListPresenter.server.ts
  • apps/webapp/app/presenters/v3/ApiRunListPresenter.server.ts
  • apps/webapp/app/presenters/v3/NextRunListPresenter.server.ts
  • apps/webapp/app/presenters/v3/PlaygroundPresenter.server.ts
  • apps/webapp/app/presenters/v3/TaskListPresenter.server.ts
  • apps/webapp/app/presenters/v3/TestPresenter.server.ts
  • apps/webapp/app/presenters/v3/TestTaskPresenter.server.ts
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.agents/route.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.playground.$agentParam/route.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.playground/route.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.test.tasks.$taskParam/AIPayloadTabContent.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.test.tasks.$taskParam/SchemaTabContent.tsx
  • apps/webapp/app/routes/api.v1.deployments.current.ts
  • apps/webapp/app/routes/realtime.v1.streams.$runId.$streamId.ts
  • apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.playground.action.tsx
  • apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.playground.realtime.v1.streams.$runId.$streamId.ts
  • apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.playground.realtime.v1.streams.$runId.input.$streamId.ts
  • apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.test.ai-generate-payload.tsx
  • apps/webapp/app/routes/runs.$runParam.ts
  • apps/webapp/app/routes/storybook.streamdown/route.tsx
  • apps/webapp/app/routes/storybook/route.tsx
  • apps/webapp/app/runEngine/concerns/queues.server.ts
  • apps/webapp/app/runEngine/services/triggerTask.server.ts
  • apps/webapp/app/runEngine/types.ts
  • apps/webapp/app/services/runsReplicationService.server.ts
  • apps/webapp/app/services/runsRepository/clickhouseRunsRepository.server.ts
  • apps/webapp/app/services/runsRepository/postgresRunsRepository.server.ts
  • apps/webapp/app/services/runsRepository/runsRepository.server.ts
  • apps/webapp/app/tailwind.css
  • apps/webapp/app/utils/pathBuilder.ts
  • apps/webapp/app/v3/services/createBackgroundWorker.server.ts
  • apps/webapp/package.json
  • apps/webapp/tailwind.config.js
  • internal-packages/clickhouse/schema/029_add_task_kind_to_task_runs_v2.sql
  • internal-packages/clickhouse/src/taskRuns.ts
  • internal-packages/database/prisma/migrations/20260329100903_add_agent_trigger_source_and_task_config/migration.sql
  • internal-packages/database/prisma/migrations/20260330113734_add_playground_conversation/migration.sql
  • internal-packages/database/prisma/migrations/20260330135232_add_messages_and_last_event_id_to_playground/migration.sql
  • internal-packages/database/prisma/schema.prisma
  • package.json
  • packages/build/package.json
  • packages/build/src/extensions/secureExec.ts
  • packages/cli-v3/src/entryPoints/managed-index-controller.ts
  • packages/cli-v3/src/mcp/config.ts
  • packages/cli-v3/src/mcp/tools.ts
  • packages/cli-v3/src/mcp/tools/agentChat.ts
  • packages/cli-v3/src/mcp/tools/agents.ts
  • packages/cli-v3/src/mcp/tools/tasks.ts
  • packages/core/package.json
  • packages/core/src/v3/apiClient/errors.ts
  • packages/core/src/v3/apiClient/index.ts
  • packages/core/src/v3/apiClient/runStream.ts
  • packages/core/src/v3/chat-client.ts
  • packages/core/src/v3/index.ts
  • packages/core/src/v3/inputStreams/index.ts
  • packages/core/src/v3/inputStreams/manager.ts
  • packages/core/src/v3/inputStreams/noopManager.ts
  • packages/core/src/v3/inputStreams/types.ts
  • packages/core/src/v3/realtimeStreams/manager.ts
  • packages/core/src/v3/realtimeStreams/noopManager.ts
  • packages/core/src/v3/realtimeStreams/streamInstance.ts
  • packages/core/src/v3/realtimeStreams/streamsWriterV1.ts
  • packages/core/src/v3/realtimeStreams/streamsWriterV2.ts
  • packages/core/src/v3/realtimeStreams/types.ts
  • packages/core/src/v3/resource-catalog/standardResourceCatalog.ts
  • packages/core/src/v3/schemas/api.ts
  • packages/core/src/v3/schemas/resources.ts
  • packages/core/src/v3/schemas/runEngine.ts
  • packages/core/src/v3/schemas/schemas.ts
  • packages/core/src/v3/types/tasks.ts
  • packages/core/test/runStream.test.ts
  • packages/trigger-sdk/package.json
  • packages/trigger-sdk/src/v3/ai.ts
  • packages/trigger-sdk/src/v3/chat-client.ts
  • packages/trigger-sdk/src/v3/chat-constants.ts
  • packages/trigger-sdk/src/v3/chat-react.ts
  • packages/trigger-sdk/src/v3/chat.test.ts
  • packages/trigger-sdk/src/v3/chat.ts
  • packages/trigger-sdk/src/v3/deployments.ts
  • packages/trigger-sdk/src/v3/index.ts
  • packages/trigger-sdk/src/v3/runs.ts
  • packages/trigger-sdk/src/v3/shared.ts
  • packages/trigger-sdk/src/v3/streams.ts
  • packages/trigger-sdk/src/v3/tasks.ts
  • patches/streamdown@2.5.0.patch
  • pnpm-workspace.yaml

Walkthrough

This change introduces AI chat agent functionality to the Trigger.dev platform. It includes new workspace routes and components for listing and interacting with deployed chat agents, new SDK exports for chat transport and client implementations, database schema extensions for conversation persistence, task trigger source filtering, Streamdown theme updates, and comprehensive streaming/WebSocket integration for bidirectional agent communication. The changes span from database migrations and service layers through UI components to core SDK type definitions and stream management.

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 3 potential issues.

View 6 additional findings in Devin Review.

Open in Devin Review

return json({ error: "payload and chatId are required" }, { status: 400 });
}

const payload = JSON.parse(payloadStr) as Record<string, any>;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Unhandled JSON.parse on user-supplied payloadStr causes 500 instead of 400

The JSON.parse(payloadStr) on line 100 is called without a try-catch on user-supplied form data. If the client sends malformed JSON (e.g., network corruption, a tampered request, or a client-side serialization bug), the action throws an unhandled exception, producing a 500 error with an HTML error boundary response. The client at playground.$agentParam/route.tsx:237 then calls response.json() on the HTML body, which fails with a confusing parse error. Note that the clientData parse on line 132-136 IS correctly wrapped in try-catch, showing this pattern was known but not applied consistently here.

Suggested change
const payload = JSON.parse(payloadStr) as Record<string, any>;
let payload: Record<string, any>;
try {
payload = JSON.parse(payloadStr) as Record<string, any>;
} catch {
return json({ error: "Invalid payload JSON" }, { status: 400 });
}
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

return json({ error: "chatId is required" }, { status: 400 });
}

const messagesData = messagesStr ? JSON.parse(messagesStr) : undefined;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Unhandled JSON.parse on user-supplied messagesStr causes 500 instead of 400

The JSON.parse(messagesStr) on line 193 is called without a try-catch on user-supplied form data. If the messages string is malformed, the action throws an unhandled exception producing a 500. The client's fire-and-forget fetch call at playground.$agentParam/route.tsx:335 silently swallows the error (.catch(() => {})), so message persistence silently fails without any feedback. Wrapping in try-catch would allow returning a proper 400 error.

Suggested change
const messagesData = messagesStr ? JSON.parse(messagesStr) : undefined;
let messagesData: unknown;
try {
messagesData = messagesStr ? JSON.parse(messagesStr) : undefined;
} catch {
return json({ error: "Invalid messages JSON" }, { status: 400 });
}
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

const tasks = await this._replica.backgroundWorkerTask.findMany({
where: {
workerId: currentWorker.id,
triggerSource: { not: "AGENT" },
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚩 TaskListPresenter now excludes AGENT tasks, may affect existing API consumers

The TaskListPresenter at line 64 now filters out tasks with triggerSource: 'AGENT' from the task list. Similarly, TestPresenter excludes agents at line 55 and 59-61. This means agents won't appear in the Tasks page or the Test page, which is the stated intent. However, any external API consumers or integrations that rely on the task list endpoint returning ALL tasks (including agents) would see a behavioral change. The agents are instead surfaced via the new dedicated Agents page.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants