You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit d6955ee
Browse filesBrowse the repository at this point in the historyBrowse files
feat(sdk,cli,core): shared webhook endpoints, webhook(), chat.event, channels and waiters
Webhooks now attach to shared endpoints. Declare a provider URL once
with `webhooks.endpoint.define({ id, source })`, then subscribe
`webhook()` tasks, `chat.event` sessions and channel connectors to it
with `{ endpoint }`, each with its own filter. Handlers receive the
endpoint the delivery arrived on, and a filter like `event.type ==
'checkout.session.completed'` narrows a union event such as
`Stripe.Event`, so the handler gets the selected event's type without a
cast.
Runs can wait for a webhook: `webhooks.waiter.create(endpoint, { match,
filter, timeout })` registers a waiter that the next matching delivery
resumes, `webhooks.waiter.wait()` suspends the run until then, and
`webhooks.waiter.cancel()` gives it up. Match paths are type-checked
against the endpoint's event, and limit, filter and cancel failures
surface as typed errors.
A `chat.event` action carries the delivery's `whd_` id as `deliveryId`
and the provider's id as `externalDeliveryId`.
A custom source can set how the endpoint answers the provider:
`webhooks.custom(config, { response: { acceptedBody: "empty" } })`
acknowledges with an empty `200`, for providers that show the response
to a user.
New named sources: `webhooks.loops()`, `webhooks.granola()`,
`webhooks.autumn()`, `webhooks.metronome()`, `webhooks.mux()`,
`webhooks.tailscale()`, `webhooks.langfuse()`, `webhooks.infisical()`,
`webhooks.planetscale()`, `webhooks.plain()`, `webhooks.firecrawl()` and
`webhooks.supabase()`. Supabase database webhooks aren't signed, so
`supabase()` checks a bearer token you add under the webhook's HTTP
headers. Retries from PagerDuty, Jira, Zendesk, Attio, Shopify, Notion,
Vercel, Typeform, Intercom, WorkOS and Firecrawl are now deduplicated on
the provider's own event or delivery id, so a retried event no longer
runs twice. Filters accept `== null` and `!= null` for presence checks,
`webhook()` takes `task()` options such as `queue` and `machine`, and a
failed channel turn posts a short error line instead of the error text
(`errorMessage` sets it, as a fixed line or a function of the error, run
id and event).
`plain()` and `metronome()` reject deliveries more than five minutes
old, matching each provider's own guidance.
For providers that batch events into an array payload, a filter can
match any of them: `event any ( type == 'nodeCreated' )`.
Mono-RevId: 7a60e96ad18a52bfb51e58a0a91885cf143c1e41
Route verified webhooks into agent sessions with `chat.event({ endpoint, key })`, and connect external chat surfaces with `chat.channels.custom({ endpoint })`. Both subscribe to a shared webhook endpoint, so an agent and your other webhook tasks can use the same provider URL. Channels support reply delivery, session binding, conversation seeding, and lifecycle reactions, and a failed turn posts a short line instead of the error (`errorMessage` sets it, as a string or a function of the failure). Use `chat.createWatchToken()` to watch a session from another surface.
7
+
8
+
A connector can also stream replies natively (`stream()`), mirror the session's state into the surface (`lifecycle()`), show tool calls as they run (`progress()`), stop a running turn from the surface (`onControl()`), post approvals and tool controls and resume the run from a verified click, download files only the surface can read (`download()`), and acknowledge or fold in messages that arrive mid-turn (`received()`, `pendingMessages`).
Add hosted webhooks: declare an endpoint once with `webhooks.endpoint.define({ id, source })` and Trigger.dev hosts its URL, verifies every request, and routes each event to the endpoint's subscribers. Subscribe tasks with `webhook({ endpoint, filter, onEvent })`, each with its own type-safe filter, and pause a run until a matching webhook arrives with `webhooks.waiter.create()` and `webhooks.waiter.wait()`.
Sources cover presets (`webhooks.stripe()`, `webhooks.github()`, `webhooks.svix()`, `webhooks.discord()`, and others), named providers (`webhooks.clerk()`, `webhooks.shopify()`, and more) and `webhooks.custom<T>(config)`, and most carry a setup prompt an AI coding agent can follow to register the endpoint. Retries are deduplicated on the provider's own event or delivery id where it sends one. Filters, keys and waiter `match` paths share the `event.`, `header.` and `webhook.` namespaces, and filters accept `== null` / `!= null` presence checks and `event any (...)` over a payload that is an array of events. `webhook()` takes `task()` options such as `queue`, `machine` and `retry`. The HTTP API lists endpoints and deliveries, replays deliveries, and creates and cancels waiters, and both it and the MCP server can read an endpoint's setup prompt and generate or store its signing secret.
Copy file name to clipboardExpand all lines: apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.playground.realtime.v1.sessions.$session.$io.append.ts
+3-1Lines changed: 3 additions & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -18,6 +18,7 @@ import { requireUserId } from "~/services/session.server";
0 commit comments