feat(sdk,slack): webhook sources, agent channels, and human-in-the-loop - #4537
feat(sdk,slack): webhook sources, agent channels, and human-in-the-loop#4537ericallam wants to merge 13 commits into
Conversation
🦋 Changeset detectedLatest commit: 4b55ab5 The changes in this PR will be included in the next version bump. This PR includes changesets to release 30 packages
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 |
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
WalkthroughAdded typed webhook sources, provider verification, webhook tasks, and durable 🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
✨ Finishing Touches 💡 2📝 Generate docstrings 💡
🛠️ Fix failing CI checks 💡
🧪 Generate unit tests (beta)
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. Comment |
| return key.replace(/\{([^}]+)\}/g, (_match, path: string) => | ||
| path.startsWith("webhook.") || path.startsWith("header.") || path.startsWith("body.") | ||
| ? `{${path}}` | ||
| : `{body.${path}}` | ||
| ); |
There was a problem hiding this comment.
Actionable comments posted: 14
🧹 Nitpick comments (9)
packages/slack/src/index.ts (3)
279-283: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick winCheck the
response_urlresponse.The code ignores the fetch result. If Slack rejects the replace (expired
response_url, invalid blocks, or a non-2xx status), the buttons stay live and clickable, and no signal reaches the caller.The connector contract treats a throw here as best-effort and logs it. Throw on failure so the outcome is visible.
♻️ Proposed change
- await fetch(responseUrl, { + const res = await fetch(responseUrl, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ replace_original: true, text: `${decision}${who}`, blocks }), }); + if (!res.ok) { + throw new Error(`slack response_url replace failed: ${res.status}`); + }
356-368: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick winHandle Slack rate limiting in
makeSlackSend.The code retries only on an auth error and only when
tokenis a function. Slack rate-limitschat.postMessageandchat.updateper channel (about one message per second, withRetry-After). Withdelivery: "stream", debounced edits reach that limit quickly. Eachratelimitedresponse then throws and fails the turn.Add a bounded retry with a delay for
ratelimited.♻️ Proposed change
let result = await post(); // Re-resolve once on an auth error (token rotation) when a resolver was supplied. if (!result.ok && typeof token === "function" && isAuthError(result.error)) { botToken = await resolve(); result = await post(); } + // Slack rate limits chat.* per channel; retry a bounded number of times. + for (let attempt = 0; attempt < 3 && !result.ok && result.error === "ratelimited"; attempt++) { + await new Promise((r) => setTimeout(r, (result.retryAfterSeconds ?? 1) * 1000)); + result = await post(); + }
400-408: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick winCheck the HTTP status before you parse the body.
slackApicallsres.json()for every response. Slack returns a non-JSON body for some non-2xx responses, for example a 429 or a 5xx from the edge.res.json()then rejects with a parse error, and the caller reports that instead of the real status. Theretry-afterheader is also lost.Return a structured error for a non-2xx response.
♻️ Proposed change
async function slackApi( baseUrl: string, method: string, token: string, body: Record<string, unknown> -): Promise<{ ok: boolean; ts?: string; error?: string }> { +): Promise<{ ok: boolean; ts?: string; error?: string; retryAfterSeconds?: number }> { const res = await fetch(`${baseUrl}/${method}`, { method: "POST", headers: { "content-type": "application/json; charset=utf-8", authorization: `Bearer ${token}`, }, body: JSON.stringify(body), }); + if (!res.ok) { + const retryAfter = Number(res.headers?.get?.("retry-after")); + return { + ok: false, + error: res.status === 429 ? "ratelimited" : `http_${res.status}`, + retryAfterSeconds: Number.isFinite(retryAfter) ? retryAfter : undefined, + }; + } return (await res.json()) as { ok: boolean; ts?: string; error?: string }; }Note: the test doubles in
packages/slack/src/index.test.tsreturn objects with only ajsonmethod. Addok: true(andheaders) to those doubles if you apply this change.packages/slack/package.json (1)
43-48: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueConsider moving
@trigger.dev/coretodevDependencies.
packages/slack/src/index.tsimports from@trigger.dev/core/v3withimport typeonly. No runtime value comes from core. Keeping core as a runtime dependency lets a consumer install a second core copy next to the one that@trigger.dev/sdkalready pulls in.If no runtime import appears later, move it to
devDependencies, or add it as a peer alongside@trigger.dev/sdk.packages/slack/src/index.test.ts (2)
11-11: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winRestore globals in
afterEach.Each test calls
vi.unstubAllGlobals()as its last statement. If an assertion fails first, or an awaited call rejects, that statement never runs. Thefetchstub then leaks into the following tests, and one failure cascades into unrelated failures.Move the cleanup into an
afterEachhook and remove the per-test calls.♻️ Proposed change
-import { describe, expect, it, vi } from "vitest"; +import { afterEach, describe, expect, it, vi } from "vitest"; import { mentions, slack, toSlackMrkdwn, type SlackMessageEvent } from "./index.js"; @@ describe("slack channel", () => { + afterEach(() => { + vi.unstubAllGlobals(); + }); +
250-260: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd a test for the token-resolver retry path.
makeSlackSendinpackages/slack/src/index.tsre-resolves the token and retries once when the token is a function and the first call returns an auth error (lines 356-361). No test covers that branch, and no test covers a function-valuedtoken.Add a case where
tokenis a resolver, the first response is{ ok: false, error: "invalid_auth" }, and the second succeeds. Assert two fetch calls and the secondauthorizationheader.Do you want me to write that test?
packages/trigger-sdk/src/v3/webhooks.ts (1)
345-359: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winReplace the 14 repeated members with one
typeof webhookSources.Each member restates
typeof webhookSources.X, and lines 368-381 restate the same 14 keys again. Any new producer requires three edits. An intersection keeps the list in one place.♻️ Proposed refactor
/** Header name used for webhook signatures */ SIGNATURE_HEADER_NAME: string; - custom: typeof webhookSources.custom; - stripe: typeof webhookSources.stripe; - github: typeof webhookSources.github; - svix: typeof webhookSources.svix; - square: typeof webhookSources.square; - discord: typeof webhookSources.discord; - clerk: typeof webhookSources.clerk; - resend: typeof webhookSources.resend; - openai: typeof webhookSources.openai; - replicate: typeof webhookSources.replicate; - recallai: typeof webhookSources.recallai; - brex: typeof webhookSources.brex; - gitlab: typeof webhookSources.gitlab; - whatsapp: typeof webhookSources.whatsapp; }Then declare the instance as
Webhooks & ProviderProducers & typeof webhookSourcesand spread...webhookSourcesin place of the 14 assignments.packages/trigger-sdk/src/v3/ai.ts (1)
4793-4832: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueDeclare
ChannelConnectoras a type alias.Every sibling in this block is a
type.ChannelConnectoris a data descriptor built by factory functions, not a behavioral contract that a class implements, so the repository rule applies.Based on learnings, keep
interfaceonly for method-shape contracts that collaborators implement; this is a data shape.As per coding guidelines: "Use types over interfaces for TypeScript".
♻️ Proposed change
-export interface ChannelConnector<TEvent = unknown> { +export type ChannelConnector<TEvent = unknown> = { id: string;Close with
};instead of}.Sources: Coding guidelines, Learnings
packages/trigger-sdk/src/v3/channelReactions.test.ts (1)
9-15: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick winAdd a case for a resolver that throws.
resolveReactionChoiceawaits a user-supplied function and does not catch. The tests coverundefined,null,"", and[], but not a throw.The behavior matters at the call sites. At
packages/trigger-sdk/src/v3/ai.tsline 6991 the call sits inside the turntry, so a throw becomes a turn error. At line 8305 the call runs after the turn already completed, and at line 8578 it runs inside the error handler. A throwingreactions.doneorreactions.errorresolver escapes there.Every other reaction step is best-effort:
applyChannelReactioncatches and logs. MakeresolveReactionChoicematch, then assert it here.💚 Proposed test and matching guard
it("skips when absent or empty", async () => { expect(await resolveReactionChoice(undefined, {})).toBeUndefined(); expect(await resolveReactionChoice("", {})).toBeUndefined(); expect(await resolveReactionChoice([], {})).toBeUndefined(); expect(await resolveReactionChoice(() => undefined, {})).toBeUndefined(); expect(await resolveReactionChoice(() => null, {})).toBeUndefined(); }); + + it("skips when the resolver throws", async () => { + expect( + await resolveReactionChoice(() => { + throw new Error("boom"); + }, {}) + ).toBeUndefined(); + });In
packages/trigger-sdk/src/v3/ai.ts:export async function resolveReactionChoice( choice: ChannelReactionChoice | undefined, event: unknown ): Promise<string | undefined> { if (choice == null) return undefined; - let value: string | string[] | null | undefined = - typeof choice === "function" ? await choice(event) : choice; + let value: string | string[] | null | undefined; + try { + value = typeof choice === "function" ? await choice(event) : choice; + } catch (error) { + logger.warn("chat.agent: reaction resolver threw; skipping reaction", { error }); + return undefined; + }
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 30f7bd73-ce46-4805-a3fb-8bb30dc30f3f
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (25)
.changeset/hosted-webhook-ingress.mddocs/ai-chat/backend.mdxdocs/ai-chat/reference.mdxdocs/docs.jsondocs/webhooks/channels.mdxdocs/webhooks/connect.mdxdocs/webhooks/deliveries.mdxdocs/webhooks/filters.mdxdocs/webhooks/human-in-the-loop.mdxdocs/webhooks/overview.mdxdocs/webhooks/session-routing.mdxdocs/webhooks/sources.mdxpackages/cli-v3/src/dev/devSupervisor.tspackages/cli-v3/src/entryPoints/dev-index-worker.tspackages/cli-v3/src/entryPoints/managed-index-worker.tspackages/slack/package.jsonpackages/slack/src/index.test.tspackages/slack/src/index.tspackages/slack/tsconfig.jsonpackages/slack/tsconfig.src.jsonpackages/slack/vitest.config.tspackages/trigger-sdk/src/v3/ai.tspackages/trigger-sdk/src/v3/channelReactions.test.tspackages/trigger-sdk/src/v3/chat.tspackages/trigger-sdk/src/v3/webhooks.ts
📜 Review details
⏰ Context from checks skipped due to timeout. (8)
- GitHub Check: webapp / 🧪 Unit Tests: Webapp (5, 12)
- GitHub Check: webapp / 🧪 Unit Tests: Webapp (11, 12)
- GitHub Check: webapp / 🧪 Unit Tests: Webapp (2, 12)
- GitHub Check: webapp / 🧪 Unit Tests: Webapp (8, 12)
- GitHub Check: webapp / 🧪 Unit Tests: Webapp (6, 12)
- GitHub Check: sdk-compat / Bun Runtime
- GitHub Check: packages / 🧪 Unit Tests: Packages (3, 3)
- GitHub Check: e2e-webapp / 🧪 E2E Tests: Webapp
🧰 Additional context used
📓 Path-based instructions (13)
**/tsconfig.json
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Use strict mode in TypeScript configuration
Files:
packages/slack/tsconfig.json
docs/**/docs.json
📄 CodeRabbit inference engine (docs/CLAUDE.md)
docs/**/docs.json: Main documentation config must be defined indocs.jsonwhich includes navigation structure, theme, and metadata
Navigation structure indocs.jsonshould be organized usingnavigation.dropdownswith groups and pages
Files:
docs/docs.json
docs/**/*.mdx
📄 CodeRabbit inference engine (docs/CLAUDE.md)
docs/**/*.mdx: MDX documentation pages must include frontmatter with title (required), description (required), and sidebarTitle (optional) in YAML format
Use Mintlify components for structured content: , , , , , , /, /
Always import from@trigger.dev/sdkin code examples (never from@trigger.dev/sdk/v3)
Code examples must be complete and runnable where possible
Use language tags in code fences:typescript,bash,jsonDocumentation in
docs/uses MDX conventions defined by the documentation guidance.
Files:
docs/webhooks/connect.mdxdocs/webhooks/deliveries.mdxdocs/webhooks/human-in-the-loop.mdxdocs/webhooks/overview.mdxdocs/webhooks/filters.mdxdocs/ai-chat/reference.mdxdocs/webhooks/session-routing.mdxdocs/webhooks/channels.mdxdocs/webhooks/sources.mdxdocs/ai-chat/backend.mdx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
**/*.{ts,tsx}: Use types over interfaces for TypeScript
Avoid using enums; prefer string unions or const objects instead
**/*.{ts,tsx}: Prefer static imports over dynamicimport(); use dynamic imports only for unresolvable circular dependencies, genuine performance code splitting, or conditional runtime loading.
Import Trigger.dev tasks from@trigger.dev/sdk; never use@trigger.dev/sdk/v3or deprecatedclient.defineJob.
Add agentcrumbs while writing code using approved namespaces; mark lines with//@Crumbsor blocks with `// `#region` `@crumbs, and strip them before merging.
Files:
packages/cli-v3/src/entryPoints/dev-index-worker.tspackages/trigger-sdk/src/v3/chat.tspackages/cli-v3/src/dev/devSupervisor.tspackages/trigger-sdk/src/v3/channelReactions.test.tspackages/cli-v3/src/entryPoints/managed-index-worker.tspackages/slack/vitest.config.tspackages/slack/src/index.test.tspackages/slack/src/index.tspackages/trigger-sdk/src/v3/webhooks.tspackages/trigger-sdk/src/v3/ai.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Use function declarations instead of default exports
Files:
packages/cli-v3/src/entryPoints/dev-index-worker.tspackages/trigger-sdk/src/v3/chat.tspackages/cli-v3/src/dev/devSupervisor.tspackages/trigger-sdk/src/v3/channelReactions.test.tspackages/cli-v3/src/entryPoints/managed-index-worker.tspackages/slack/vitest.config.tspackages/slack/src/index.test.tspackages/slack/src/index.tspackages/trigger-sdk/src/v3/webhooks.tspackages/trigger-sdk/src/v3/ai.ts
**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/otel-metrics.mdc)
**/*.ts: When creating or editing OTEL metrics (counters, histograms, gauges), ensure metric attributes have low cardinality by using only enums, booleans, bounded error codes, or bounded shard IDs
Do not use high-cardinality attributes in OTEL metrics such as UUIDs/IDs (envId, userId, runId, projectId, organizationId), unbounded integers (itemCount, batchSize, retryCount), timestamps (createdAt, startTime), or free-form strings (errorMessage, taskName, queueName)
When exporting OTEL metrics via OTLP to Prometheus, be aware that the exporter automatically adds unit suffixes to metric names (e.g., 'my_duration_ms' becomes 'my_duration_ms_milliseconds', 'my_counter' becomes 'my_counter_total'). Account for these transformations when writing Grafana dashboards or Prometheus queries
Files:
packages/cli-v3/src/entryPoints/dev-index-worker.tspackages/trigger-sdk/src/v3/chat.tspackages/cli-v3/src/dev/devSupervisor.tspackages/trigger-sdk/src/v3/channelReactions.test.tspackages/cli-v3/src/entryPoints/managed-index-worker.tspackages/slack/vitest.config.tspackages/slack/src/index.test.tspackages/slack/src/index.tspackages/trigger-sdk/src/v3/webhooks.tspackages/trigger-sdk/src/v3/ai.ts
packages/cli-v3/src/entryPoints/**/*
📄 CodeRabbit inference engine (packages/cli-v3/CLAUDE.md)
Code in
src/entryPoints/runs inside customer containers and is a different runtime environment from the CLI - changes affect deployed task execution directly
Files:
packages/cli-v3/src/entryPoints/dev-index-worker.tspackages/cli-v3/src/entryPoints/managed-index-worker.ts
packages/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
For public packages, use
buildfor verification.
Files:
packages/cli-v3/src/entryPoints/dev-index-worker.tspackages/trigger-sdk/src/v3/chat.tspackages/cli-v3/src/dev/devSupervisor.tspackages/trigger-sdk/src/v3/channelReactions.test.tspackages/cli-v3/src/entryPoints/managed-index-worker.tspackages/slack/vitest.config.tspackages/slack/src/index.test.tspackages/slack/src/index.tspackages/trigger-sdk/src/v3/webhooks.tspackages/trigger-sdk/src/v3/ai.ts
packages/trigger-sdk/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
In the Trigger.dev SDK (packages/trigger-sdk), prefer isomorphic code like fetch and ReadableStream instead of Node.js-specific code
Files:
packages/trigger-sdk/src/v3/chat.tspackages/trigger-sdk/src/v3/channelReactions.test.tspackages/trigger-sdk/src/v3/webhooks.tspackages/trigger-sdk/src/v3/ai.ts
packages/trigger-sdk/**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (packages/trigger-sdk/CLAUDE.md)
Always import from
@trigger.dev/sdk. Never use@trigger.dev/sdk/v3(deprecated path alias)
Files:
packages/trigger-sdk/src/v3/chat.tspackages/trigger-sdk/src/v3/channelReactions.test.tspackages/trigger-sdk/src/v3/webhooks.tspackages/trigger-sdk/src/v3/ai.ts
packages/cli-v3/src/dev/**/*
📄 CodeRabbit inference engine (packages/cli-v3/CLAUDE.md)
Dev mode code should be located in
src/dev/and runs tasks locally in the user's Node.js process without containers
Files:
packages/cli-v3/src/dev/devSupervisor.ts
**/*.{test,spec}.{ts,tsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Use vitest for all tests in the Trigger.dev repository
**/*.{test,spec}.{ts,tsx}: Use Vitest exclusively and never mock dependencies; use Testcontainers for integration dependencies.
Place test files next to the source files they test.
Files:
packages/trigger-sdk/src/v3/channelReactions.test.tspackages/slack/src/index.test.ts
**/package.json
📄 CodeRabbit inference engine (AGENTS.md)
When adding Zod, use the exact repository-wide pinned version
3.25.76, never a different version or range.
Files:
packages/slack/package.json
🧠 Learnings (21)
📚 Learning: 2026-03-10T12:44:14.176Z
Learnt from: nicktrn
Repo: triggerdotdev/trigger.dev PR: 3200
File: docs/config/config-file.mdx:353-368
Timestamp: 2026-03-10T12:44:14.176Z
Learning: In the trigger.dev repo, docs PRs are often companions to implementation PRs. When reviewing docs PRs (MDX files under docs/), check the PR description for any companion/related PR references and verify that the documented features exist in those companion PRs before flagging missing implementations. This ensures docs stay in sync with code changes across related PRs.
Applied to files:
docs/webhooks/connect.mdxdocs/webhooks/deliveries.mdxdocs/webhooks/human-in-the-loop.mdxdocs/webhooks/overview.mdxdocs/webhooks/filters.mdxdocs/ai-chat/reference.mdxdocs/webhooks/session-routing.mdxdocs/webhooks/channels.mdxdocs/webhooks/sources.mdxdocs/ai-chat/backend.mdx
📚 Learning: 2026-04-30T20:30:29.458Z
Learnt from: ericallam
Repo: triggerdotdev/trigger.dev PR: 3226
File: docs/ai-chat/quick-start.mdx:13-13
Timestamp: 2026-04-30T20:30:29.458Z
Learning: In this repo’s documentation MDX files (`docs/**/*.mdx`), use `ts` and `tsx` (not `typescript`) as the code-fence language tags for TypeScript/TSX snippets. Do not flag `ts`/`tsx` code-fence language tags as incorrect in any docs MDX file, since this is the site-wide Mintlify-compatible convention.
Applied to files:
docs/webhooks/connect.mdxdocs/webhooks/deliveries.mdxdocs/webhooks/human-in-the-loop.mdxdocs/webhooks/overview.mdxdocs/webhooks/filters.mdxdocs/ai-chat/reference.mdxdocs/webhooks/session-routing.mdxdocs/webhooks/channels.mdxdocs/webhooks/sources.mdxdocs/ai-chat/backend.mdx
📚 Learning: 2026-03-22T13:26:12.060Z
Learnt from: ericallam
Repo: triggerdotdev/trigger.dev PR: 3244
File: apps/webapp/app/components/code/TextEditor.tsx:81-86
Timestamp: 2026-03-22T13:26:12.060Z
Learning: In the triggerdotdev/trigger.dev codebase, do not flag `navigator.clipboard.writeText(...)` calls for `missing-await`/`unhandled-promise` issues. These clipboard writes are intentionally invoked without `await` and without `catch` handlers across the project; keep that behavior consistent when reviewing TypeScript/TSX files (e.g., usages like in `apps/webapp/app/components/code/TextEditor.tsx`).
Applied to files:
packages/cli-v3/src/entryPoints/dev-index-worker.tspackages/trigger-sdk/src/v3/chat.tspackages/cli-v3/src/dev/devSupervisor.tspackages/trigger-sdk/src/v3/channelReactions.test.tspackages/cli-v3/src/entryPoints/managed-index-worker.tspackages/slack/vitest.config.tspackages/slack/src/index.test.tspackages/slack/src/index.tspackages/trigger-sdk/src/v3/webhooks.tspackages/trigger-sdk/src/v3/ai.ts
📚 Learning: 2026-03-22T19:24:14.403Z
Learnt from: matt-aitken
Repo: triggerdotdev/trigger.dev PR: 3187
File: apps/webapp/app/v3/services/alerts/deliverErrorGroupAlert.server.ts:200-204
Timestamp: 2026-03-22T19:24:14.403Z
Learning: In the triggerdotdev/trigger.dev codebase, webhook URLs are not expected to contain embedded credentials/secrets (e.g., fields like `ProjectAlertWebhookProperties` should only hold credential-free webhook endpoints). During code review, if you see logging or inclusion of raw webhook URLs in error messages, do not automatically treat it as a credential-leak/secrets-in-logs issue by default—first verify the URL does not contain embedded credentials (for example, no username/password in the URL, no obvious secret/token query params or fragments). If the URL is credential-free per this project’s conventions, allow the logging.
Applied to files:
packages/cli-v3/src/entryPoints/dev-index-worker.tspackages/trigger-sdk/src/v3/chat.tspackages/cli-v3/src/dev/devSupervisor.tspackages/trigger-sdk/src/v3/channelReactions.test.tspackages/cli-v3/src/entryPoints/managed-index-worker.tspackages/slack/vitest.config.tspackages/slack/src/index.test.tspackages/slack/src/index.tspackages/trigger-sdk/src/v3/webhooks.tspackages/trigger-sdk/src/v3/ai.ts
📚 Learning: 2026-05-18T08:21:27.694Z
Learnt from: d-cs
Repo: triggerdotdev/trigger.dev PR: 3632
File: apps/webapp/sentry.server.ts:4-21
Timestamp: 2026-05-18T08:21:27.694Z
Learning: When handling Prisma error P1001 ("Can't reach database server") in TypeScript, don’t assume a single error shape. Prisma can surface P1001 via two different error classes/fields: `PrismaClientKnownRequestError` exposes it as `err.code === "P1001"` (common during mid-query connection drops), while `PrismaClientInitializationError` exposes it as `err.errorCode === "P1001"` (common on client startup failure). Therefore, predicates should use `err.code === "P1001" || err.errorCode === "P1001"`. Do not flag `err.code === "P1001"` as “unreachable/never matches,” as it is expected in production.
Applied to files:
packages/cli-v3/src/entryPoints/dev-index-worker.tspackages/trigger-sdk/src/v3/chat.tspackages/cli-v3/src/dev/devSupervisor.tspackages/trigger-sdk/src/v3/channelReactions.test.tspackages/cli-v3/src/entryPoints/managed-index-worker.tspackages/slack/vitest.config.tspackages/slack/src/index.test.tspackages/slack/src/index.tspackages/trigger-sdk/src/v3/webhooks.tspackages/trigger-sdk/src/v3/ai.ts
📚 Learning: 2026-05-18T08:21:27.694Z
Learnt from: d-cs
Repo: triggerdotdev/trigger.dev PR: 3632
File: apps/webapp/sentry.server.ts:4-21
Timestamp: 2026-05-18T08:21:27.694Z
Learning: When handling Prisma errors for P1001 ("Can't reach database server"), do not assume it only appears under a single property name. Prisma may surface P1001 via either `PrismaClientKnownRequestError` (`err.code === "P1001"`, e.g., mid-query connection drops) or `PrismaClientInitializationError` (`err.errorCode === "P1001"`, e.g., client startup connection failure). To reliably detect the condition, check `err.code === "P1001" || err.errorCode === "P1001"`, and avoid review rules that would incorrectly flag `err.code === "P1001"` as unreachable/never-matching.
Applied to files:
packages/cli-v3/src/entryPoints/dev-index-worker.tspackages/trigger-sdk/src/v3/chat.tspackages/cli-v3/src/dev/devSupervisor.tspackages/trigger-sdk/src/v3/channelReactions.test.tspackages/cli-v3/src/entryPoints/managed-index-worker.tspackages/slack/vitest.config.tspackages/slack/src/index.test.tspackages/slack/src/index.tspackages/trigger-sdk/src/v3/webhooks.tspackages/trigger-sdk/src/v3/ai.ts
📚 Learning: 2026-06-13T19:53:13.759Z
Learnt from: ericallam
Repo: triggerdotdev/trigger.dev PR: 3937
File: packages/trigger-sdk/skills/realtime-and-frontend/SKILL.md:258-260
Timestamp: 2026-06-13T19:53:13.759Z
Learning: When reviewing code that uses `trigger.dev/react-hooks`’s `useRealtimeRun`, preserve the call signature where the first argument is the full realtime handle object (not `handle.id`). This is intentional to maintain type-safety and is consistent with the official docs; do not suggest changing the first argument from the handle object to `handle.id`.
Applied to files:
packages/cli-v3/src/entryPoints/dev-index-worker.tspackages/trigger-sdk/src/v3/chat.tspackages/cli-v3/src/dev/devSupervisor.tspackages/trigger-sdk/src/v3/channelReactions.test.tspackages/cli-v3/src/entryPoints/managed-index-worker.tspackages/slack/vitest.config.tspackages/slack/src/index.test.tspackages/slack/src/index.tspackages/trigger-sdk/src/v3/webhooks.tspackages/trigger-sdk/src/v3/ai.ts
📚 Learning: 2026-06-17T17:13:49.929Z
Learnt from: matt-aitken
Repo: triggerdotdev/trigger.dev PR: 3948
File: apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.bulk-actions.$bulkActionParam/route.tsx:48-62
Timestamp: 2026-06-17T17:13:49.929Z
Learning: In triggerdotdev/trigger.dev, within `dashboardLoader`/`dashboardAction` (or similar context resolver code) whenever you resolve an organization ID from an organization slug for RBAC/enterprise authorization scope, always read from the primary Prisma client (`prisma`), not `$replica`. Using `$replica` can hit replica-lag and cause the RBAC lookup/authorization to run without the correct org scope (bypassing intended role enforcement). Implement the slug→org lookup with `prisma.organization.findFirst(...)` (or equivalent primary-client query) and add an inline comment documenting why the primary client is required (replica lag could lead to unscoped RBAC checks).
Applied to files:
packages/cli-v3/src/entryPoints/dev-index-worker.tspackages/trigger-sdk/src/v3/chat.tspackages/cli-v3/src/dev/devSupervisor.tspackages/trigger-sdk/src/v3/channelReactions.test.tspackages/cli-v3/src/entryPoints/managed-index-worker.tspackages/slack/vitest.config.tspackages/slack/src/index.test.tspackages/slack/src/index.tspackages/trigger-sdk/src/v3/webhooks.tspackages/trigger-sdk/src/v3/ai.ts
📚 Learning: 2026-06-23T13:04:21.413Z
Learnt from: carderne
Repo: triggerdotdev/trigger.dev PR: 4023
File: apps/webapp/app/services/upsertBranch.server.ts:14-18
Timestamp: 2026-06-23T13:04:21.413Z
Learning: In TypeScript, it’s valid to `import { type X }` and then use `typeof X` in a type-only position, e.g. `type Alias = z.infer<typeof X>`. The `type` modifier suppresses the runtime import, but the type checker still has the full exported type so `z.infer<typeof X>` can resolve correctly. In code reviews, don’t flag this as a TypeScript compile error as long as `typeof X` is used in a type context (e.g., with `z.infer`, `type` aliases, generics), not as a runtime value.
Applied to files:
packages/cli-v3/src/entryPoints/dev-index-worker.tspackages/trigger-sdk/src/v3/chat.tspackages/cli-v3/src/dev/devSupervisor.tspackages/trigger-sdk/src/v3/channelReactions.test.tspackages/cli-v3/src/entryPoints/managed-index-worker.tspackages/slack/vitest.config.tspackages/slack/src/index.test.tspackages/slack/src/index.tspackages/trigger-sdk/src/v3/webhooks.tspackages/trigger-sdk/src/v3/ai.ts
📚 Learning: 2026-06-04T18:16:35.386Z
Learnt from: nicktrn
Repo: triggerdotdev/trigger.dev PR: 3836
File: apps/supervisor/src/backpressure/backpressureMonitor.ts:3-5
Timestamp: 2026-06-04T18:16:35.386Z
Learning: When reviewing TypeScript in this repo, apply the rule “prefer type aliases over interfaces” only to data/object shapes and union/intersection type modeling. If an interface is being used as a behavioral contract for collaborators to implement (e.g., method-shape interfaces that define required behavior, such as `BackpressureLogger` / `BackpressureSignalSource` in `apps/supervisor/src/backpressure/backpressureMonitor.ts`), keep it as an `interface` and do not flag it as a type-alias-vs-interface violation.
Applied to files:
packages/cli-v3/src/entryPoints/dev-index-worker.tspackages/trigger-sdk/src/v3/chat.tspackages/cli-v3/src/dev/devSupervisor.tspackages/trigger-sdk/src/v3/channelReactions.test.tspackages/cli-v3/src/entryPoints/managed-index-worker.tspackages/slack/vitest.config.tspackages/slack/src/index.test.tspackages/slack/src/index.tspackages/trigger-sdk/src/v3/webhooks.tspackages/trigger-sdk/src/v3/ai.ts
📚 Learning: 2026-06-09T17:58:04.699Z
Learnt from: 0ski
Repo: triggerdotdev/trigger.dev PR: 3879
File: apps/webapp/app/models/vercelIntegration.server.ts:619-630
Timestamp: 2026-06-09T17:58:04.699Z
Learning: In this codebase, outbound raw `fetch` calls should typically rely on Node/undici’s default request timeout (about ~300s) rather than adding a per-call `AbortController` + `setTimeout` wrapper inside individual functions (e.g. in files like `apps/webapp/app/models/vercelIntegration.server.ts`). During code review, do not flag the absence of a per-call timeout on a single `fetch` as an issue; if per-call timeouts are needed, they should be implemented via a codebase-wide convention (e.g., a shared fetch wrapper or documented pattern) rather than ad-hoc per-function changes.
Applied to files:
packages/cli-v3/src/entryPoints/dev-index-worker.tspackages/trigger-sdk/src/v3/chat.tspackages/cli-v3/src/dev/devSupervisor.tspackages/trigger-sdk/src/v3/channelReactions.test.tspackages/cli-v3/src/entryPoints/managed-index-worker.tspackages/slack/vitest.config.tspackages/slack/src/index.test.tspackages/slack/src/index.tspackages/trigger-sdk/src/v3/webhooks.tspackages/trigger-sdk/src/v3/ai.ts
📚 Learning: 2026-03-31T21:37:27.212Z
Learnt from: isshaddad
Repo: triggerdotdev/trigger.dev PR: 3283
File: docs/migration-n8n.mdx:19-21
Timestamp: 2026-03-31T21:37:27.212Z
Learning: When reviewing code in `packages/trigger-sdk/src/v3`, treat `tasks.triggerAndWait()` and `tasks.batchTriggerAndWait()` as real exported APIs. They are defined in `shared.ts` and re-exported via the `tasks` object in `tasks.ts`, and they take the task ID string as their first argument (not a task instance). This is distinct from the instance methods `yourTask.triggerAndWait()` and `yourTask.batchTriggerAndWait()`. Do not flag calls to `tasks.triggerAndWait()` or `tasks.batchTriggerAndWait()` as non-existent or incorrectly invoked.
Applied to files:
packages/trigger-sdk/src/v3/chat.tspackages/trigger-sdk/src/v3/channelReactions.test.tspackages/trigger-sdk/src/v3/webhooks.tspackages/trigger-sdk/src/v3/ai.ts
📚 Learning: 2026-05-17T08:08:12.370Z
Learnt from: ericallam
Repo: triggerdotdev/trigger.dev PR: 3644
File: packages/trigger-sdk/src/v3/ai.ts:8695-8746
Timestamp: 2026-05-17T08:08:12.370Z
Learning: In the Trigger v3 session resume/streams logic, ensure session resumption uses sequence cursors rather than timestamps. Specifically: for each turn-complete control record written to `session.out`, include a `session-in-event-id` header whose value is the committed-consume cursor (`session.in.lastDispatchedSeqNum`). On boot/resume, scan `session.out` for the latest turn-complete record, read the `session-in-event-id` header, and seed the `sessionStreams` manager for `.in` using both `lastSeqNum` and `lastDispatchedSeqNum` so previously processed user messages are not replayed. Do not use `setMinTimestamp`/`lastOutTimestamp` for resume ordering in this flow.
Applied to files:
packages/trigger-sdk/src/v3/chat.tspackages/trigger-sdk/src/v3/channelReactions.test.tspackages/trigger-sdk/src/v3/webhooks.tspackages/trigger-sdk/src/v3/ai.ts
📚 Learning: 2026-05-18T14:19:56.437Z
Learnt from: ericallam
Repo: triggerdotdev/trigger.dev PR: 3655
File: packages/trigger-sdk/src/v3/ai.ts:8667-8731
Timestamp: 2026-05-18T14:19:56.437Z
Learning: In the Trigger SDK (v3) when making raw `fetch` calls to the Trigger API (including override paths such as `createChatStartSessionAction`), set the request headers to match `ApiClient`: `Content-Type`, `Authorization`, and `x-trigger-source: "sdk"`. Also forward the current preview branch by setting `x-trigger-branch` to `apiClientManager.branchName`. Prefer using the shared `overrideRequestHeaders(accessToken)` helper instead of manually constructing headers, so requests route correctly to preview environments.
Applied to files:
packages/trigger-sdk/src/v3/chat.tspackages/trigger-sdk/src/v3/channelReactions.test.tspackages/trigger-sdk/src/v3/webhooks.tspackages/trigger-sdk/src/v3/ai.ts
📚 Learning: 2026-05-19T22:37:47.286Z
Learnt from: ericallam
Repo: triggerdotdev/trigger.dev PR: 3671
File: packages/trigger-sdk/test/recovery-boot.test.ts:456-457
Timestamp: 2026-05-19T22:37:47.286Z
Learning: In `packages/trigger-sdk` (Trigger.dev SDK), `logger.warn` (and other SDK logger methods) should route to the Trigger.dev structured logger sink, not to `console.warn`. In SDK tests, `vi.spyOn(console, "warn")` (or similar console spies) should only be used to suppress stray console output; reviewers should not suggest asserting on `console.warn` spies to verify SDK-internal warning/fallback log behavior. Use the SDK’s structured-logger outputs/capture approach instead of console spies.
Applied to files:
packages/trigger-sdk/src/v3/chat.tspackages/trigger-sdk/src/v3/channelReactions.test.tspackages/trigger-sdk/src/v3/webhooks.tspackages/trigger-sdk/src/v3/ai.ts
📚 Learning: 2026-05-18T14:40:02.173Z
Learnt from: ericallam
Repo: triggerdotdev/trigger.dev PR: 3658
File: packages/core/src/v3/realtimeStreams/manager.test.ts:1-147
Timestamp: 2026-05-18T14:40:02.173Z
Learning: In this repo’s trigger.dev codebase, the “never mock — use testcontainers” guideline should only be applied to integration tests that talk to real external services (e.g., Redis, Postgres, S2). For unit tests that validate in-memory logic (e.g., deduplication/cache behavior in StandardRealtimeStreamsManager and similar module-boundary call counting), it is allowed to use Vitest mocks like `vi.fn()` and to stub/mock `ApiClient` objects to count calls or simulate in-process collaborators. Do not flag `vi.fn()`-based mocks as policy violations in these unit-test scenarios; reserve the rule for true external-service integration tests.
Applied to files:
packages/trigger-sdk/src/v3/channelReactions.test.tspackages/slack/src/index.test.ts
📚 Learning: 2026-05-18T14:40:02.173Z
Learnt from: ericallam
Repo: triggerdotdev/trigger.dev PR: 3658
File: packages/core/src/v3/realtimeStreams/manager.test.ts:1-147
Timestamp: 2026-05-18T14:40:02.173Z
Learning: In the triggerdotdev/trigger.dev repo, the policy “Never mock anything — use testcontainers instead” should only be enforced for integration tests that interact with real external services (e.g., Redis, Postgres) via actual infrastructure. For unit tests that exercise pure in-memory logic (e.g., cache semantics) it is OK to stub collaborators such as `ApiClient` using Vitest (`vi.fn()`) to assert call counts or control behavior. Do not flag `vi.fn()`-based `ApiClient` stubs in unit tests as violations of the testcontainers policy.
Applied to files:
packages/trigger-sdk/src/v3/channelReactions.test.tspackages/slack/src/index.test.ts
📚 Learning: 2026-06-16T09:19:47.637Z
Learnt from: d-cs
Repo: triggerdotdev/trigger.dev PR: 3960
File: apps/webapp/test/prismaInfrastructureErrorCapture.test.ts:0-0
Timestamp: 2026-06-16T09:19:47.637Z
Learning: In this repo’s Vitest setup, `vitest.config.ts` uses `globals: true`, so identifiers like `vi`, `describe`, `it`, and `expect` are available as globals in Vitest test files. During code review, do not flag missing `vi`/`describe`/`it`/`expect` imports as a runtime error or correctness issue when they’re used in `*.test.ts/tsx` or `*.spec.ts/tsx` files. Explicit imports are still preferred for consistency, but they’re not required for runtime behavior.
Applied to files:
packages/trigger-sdk/src/v3/channelReactions.test.tspackages/slack/src/index.test.ts
📚 Learning: 2026-05-01T15:45:08.099Z
Learnt from: matt-aitken
Repo: triggerdotdev/trigger.dev PR: 3499
File: packages/plugins/tsup.config.ts:3-3
Timestamp: 2026-05-01T15:45:08.099Z
Learning: In build/tool configuration files (e.g., tsup.config.ts, vite.config.ts, vitest.config.ts), follow the tool’s documented export pattern and use `export default defineConfig(...)` (or the equivalent documented default export). The repo-wide guideline “use named exports instead of default exports” should apply only to application code (*.{ts,tsx,js,jsx}), not to these build/tool config files—so do not flag `export default defineConfig(...)` in these config files as a violation.
Applied to files:
packages/slack/vitest.config.ts
📚 Learning: 2026-06-16T13:14:09.440Z
Learnt from: ericallam
Repo: triggerdotdev/trigger.dev PR: 3964
File: docs/ai-chat/reference.mdx:482-482
Timestamp: 2026-06-16T13:14:09.440Z
Learning: When documenting or reviewing usage of `ChatTurn.complete(source?)` (in `packages/trigger-sdk/src/v3/ai.ts`), note that `source` is optional (`source?: UIMessageStreamable`). Calling `complete()` with no `source` is valid specifically for a final head-start handover (`handover.isFinal`), because the warm partial already contains the response. If examples or guidance omit `source`, ensure they are in this final-hand-over context so they remain correct.
Applied to files:
docs/ai-chat/reference.mdxdocs/ai-chat/backend.mdx
📚 Learning: 2026-06-16T13:14:14.382Z
Learnt from: ericallam
Repo: triggerdotdev/trigger.dev PR: 3964
File: docs/ai-chat/reference.mdx:478-478
Timestamp: 2026-06-16T13:14:14.382Z
Learning: When reviewing RC-gated `ai-chat` docs under `docs/ai-chat/`, don’t immediately flag missing SDK type fields or implementation details just because the field isn’t present on the docs branch yet. Instead, find and cross-check the companion implementation PR that’s intended to land alongside the docs PR, and only report missing/incorrect fields if they are also absent in the companion SDK/type changes.
Applied to files:
docs/ai-chat/reference.mdxdocs/ai-chat/backend.mdx
🪛 GitHub Actions: 📦 Preview packages (pkg.pr.new) / 0_Build and publish previews.txt
packages/trigger-sdk/src/v3/ai.ts
[error] 39-39: TypeScript build failed: Module '@trigger.dev/core/v3' has no exported member 'AnyChatEvent' (TS2305). Failed command: tshy.
🪛 GitHub Actions: 📦 Preview packages (pkg.pr.new) / Build and publish previews
packages/trigger-sdk/src/v3/ai.ts
[error] 39-39: TypeScript build failed in '@trigger.dev/sdk:build': Module '@trigger.dev/core/v3' has no exported member 'AnyChatEvent' (TS2305).
🪛 GitHub Check: code-quality / code-quality
packages/slack/src/index.test.ts
[warning] 97-97: eslint(no-unsafe-optional-chaining)
Unsafe usage of optional chaining
[warning] 48-48: eslint(no-unsafe-optional-chaining)
Unsafe usage of optional chaining
🪛 GitHub Check: CodeQL
packages/slack/src/index.ts
[failure] 306-307: Polynomial regular expression used on uncontrolled data
This regular expression that depends on library input may run slow on strings starting with '[' and with many repetitions of '[\'.
This regular expression that depends on library input may run slow on strings starting with '[\](http://' and with many repetitions of '[!](http://'.
packages/trigger-sdk/src/v3/webhooks.ts
[failure] 309-313: Polynomial regular expression used on uncontrolled data
This regular expression that depends on library input may run slow on strings starting with '{{' and with many repetitions of '{{|'.
This regular expression that depends on library input may run slow on strings starting with '{{' and with many repetitions of '{{|'.
This regular expression that depends on library input may run slow on strings starting with '{{' and with many repetitions of '{{|'.
This regular expression that depends on library input may run slow on strings starting with '{{' and with many repetitions of '{{|'.
🪛 LanguageTool
.changeset/hosted-webhook-ingress.md
[uncategorized] ~10-~10: The official name of this software platform is spelled with a capital “H”.
Context: ...rce with a preset (webhooks.stripe(), webhooks.github(), and others) or `webhooks.custom(...
(GITHUB)
docs/webhooks/sources.mdx
[uncategorized] ~53-~53: The official name of this software platform is spelled with a capital “H”.
Context: ... The available presets are stripe(), github(), svix(), square(), and `discord(...
(GITHUB)
🔇 Additional comments (36)
docs/webhooks/overview.mdx (1)
1-96: LGTM!docs/webhooks/connect.mdx (1)
1-35: LGTM!docs/webhooks/deliveries.mdx (1)
1-48: LGTM!docs/webhooks/filters.mdx (1)
1-87: LGTM!Also applies to: 97-99
docs/webhooks/session-routing.mdx (1)
1-96: LGTM!docs/webhooks/channels.mdx (1)
20-28: LGTM!Also applies to: 38-134
docs/webhooks/human-in-the-loop.mdx (1)
1-100: LGTM!Also applies to: 121-143
docs/ai-chat/backend.mdx (1)
473-502: LGTM!docs/ai-chat/reference.mdx (1)
50-51: LGTM!Also applies to: 506-507, 537-572
docs/docs.json (1)
150-162: LGTM!.changeset/hosted-webhook-ingress.md (1)
1-14: LGTM!packages/cli-v3/src/dev/devSupervisor.ts (1)
35-35: LGTM!packages/slack/src/index.ts (7)
39-83: LGTM!
125-133: LGTM!
141-189: LGTM!
237-247: LGTM!
286-297: LGTM!
328-333: LGTM!
377-392: LGTM!packages/slack/tsconfig.json (1)
1-8: LGTM!packages/slack/vitest.config.ts (1)
1-8: LGTM!packages/slack/src/index.test.ts (1)
12-46: LGTM!Also applies to: 115-248, 262-306
packages/slack/tsconfig.src.json (1)
5-11: 📐 Maintainability & Code QualityNo change needed for
types: ["node"].
@types/nodeis available through the workspace dependency, and TypeScript type-only resolution does not require@types/nodeto be declared by each package that references it.> Likely an incorrect or invalid review comment.packages/trigger-sdk/src/v3/webhooks.ts (4)
199-260: LGTM!
262-295: LGTM!
308-314: 🔒 Security & PrivacyThe CodeQL ReDoS finding is a false positive at this call site.
[^}]+is a negated class bounded by literal{and}. It has no ambiguous alternation, so the worst case is quadratic, not exponential, and only on input with many unclosed{.The input is the
keytemplate that the developer writes in source and that runs once during indexing. It is not request data. Dismiss the alert or add a suppression comment so the check stops failing the pipeline.Source: Linters/SAST tools
163-177: 🎯 Functional CorrectnessNo change needed.
gitlabcan use the GitLab signing-token preset when configured, andX-Hub-Signature-256scheme.packages/trigger-sdk/src/v3/ai.ts (7)
39-46: LGTM!Also applies to: 61-61, 183-193
1266-1300: LGTM!
4840-4917: LGTM!Also applies to: 4919-5047
5113-5132: LGTM!Also applies to: 5235-5253, 5896-5920
6294-6297: LGTM!
8261-8315: LGTM!
8818-8863: LGTM!Also applies to: 11399-11402, 11417-11418
packages/trigger-sdk/src/v3/chat.ts (1)
100-117: LGTM!packages/trigger-sdk/src/v3/channelReactions.test.ts (1)
17-38: LGTM!
b4b9f89 to
274c3ab
Compare
@trigger.dev/build
trigger.dev
@trigger.dev/core
@trigger.dev/python
@trigger.dev/react-hooks
@trigger.dev/redis-worker
@trigger.dev/rsc
@trigger.dev/schema-to-json
@trigger.dev/slack
@trigger.dev/sdk
commit: |
0430f92 to
481f6c1
Compare
The deploy path now forwards declared webhooks to the server the same way dev does, so hosted webhook endpoints are created and stay active on deploy instead of only working under trigger dev.
Two webhook() declarations sharing an id used to silently overwrite each other in the worker manifest. Indexing now fails with the colliding ids and their file paths, matching how duplicate task ids are already handled.
The HITL approval block serialized the tool input without a bound into a Slack section text field, which is capped near 3000 characters. A large input made chat.postMessage fail with invalid_blocks so the approve and deny controls never appeared. The serialized input is now capped to keep the block within the limit.
…g a turn A channel interaction callback (for example a Slack button click) that resolves to a tool call with no matching pending tool part is a stale or duplicate callback. It was falling through to the inbound-message path, which acked, reacted, and ran a full agent turn. Such callbacks are now dropped: no turn runs and the run returns to its idle wait for the next message.
87c5f8b to
d915b8f
Compare
The HITL renderer only posted approve/deny buttons for the first pending tool call, so when a turn paused on multiple tool approvals the rest never got controls and the turn could not finish. It now renders a section plus an approve/deny pair for each pending call.
…isting The Slack package sets types: ["node"] in its tsconfig but did not declare @types/node, so type resolution depended on workspace hoisting. Declare it at the repo-pinned version, matching the other packages that opt into node types. vitest stays root-provided, consistent with every other package.
The channels setup listed only chat:write, which posts replies but does not grant read access to message.channels events. Add channels:history to the app scopes and note that adding scopes after install requires a reinstall.
…king The link replacement in toSlackMrkdwn used unbounded character classes, which can backtrack quadratically on pathological input. Bound the link text and URL lengths and exclude newlines. Also tightened two test assertions that used unsafe optional chaining.
Several webhook doc code blocks used webhook, webhooks, streamText, anthropic, or chat without importing them, so a copied snippet would not type-check on its own. Add the imports to the standalone examples across sources, filters, channels, and human-in-the-loop.
Add channel-event delivery to the mockChatAgent harness (sendChannelEvent) and a recordingChannelConnector helper to @trigger.dev/sdk/ai/test, so a chat.agent's channel round-trip (inbound mapping, ack placeholder, egress send, edit-in-place, and lifecycle reactions) can be driven and asserted entirely offline.
Three fixes to chat.agent channel egress: The debounced stream editor now re-arms after an edit it skipped because a previous edit was still in flight, so text buffered during that window still reaches the channel instead of stalling until the next delta. The stream editor is stopped when the reply stream is aborted or cancelled, not just on normal completion, so a late timer can no longer edit the channel message after the turn has ended. A turn that throws now edits the placeholder to show the error, so a channel user sees the failure instead of a message stuck on the loading placeholder.
Add a fire-and-forget deliverChannelEvent to the harness and loop-level tests for the channel interaction paths: a resolved interaction callback resumes the pending tool and finalizes the controls, and a stale callback that matches no pending tool is dropped without running a turn or posting anything.
Summary
The public SDK and docs half of hosted webhooks:
webhook()with typed provider sources (webhooks.stripe(),webhooks.github(),webhooks.svix(), and more, pluswebhooks.custom<T>()),chat.eventandchat.channelsfor agent channels, human-in-the-loop tool approvals, the new@trigger.dev/slackconnector, and the webhooks docs section.Stacked on the server PR
This is the top of a stack. Its base is #4344 (the server half: ingress, delivery pipeline, dashboard, and the shared
@trigger.dev/coreschemas this SDK builds on), so the diff here is API-only and it builds against a base that already has core.The single changeset in this PR bumps
@trigger.dev/core,@trigger.dev/sdk,@trigger.dev/slack, andtrigger.devtogether, so core (whose code lands via #4344) is published alongside the SDK.Merge order
Merges after #4344. The plan: land and deploy the server behind its flag, cut prerelease (rc) packages for early users to test against the live environment, then merge this and cut the real release once the feature is live. When #4344 merges, GitHub retargets this PR's base to
mainautomatically.