chore: consolidate chat.agent / Sessions / Skills changesets (26 → 8)

Roll up all the chat.agent feature work that's been accumulating on this
branch into 8 user-facing CHANGELOG entries. No behavior change — just
tidying up the .changeset/ directory before merge.

Final shape:

- chat-agent.md (sdk minor + core patch) — the headline; folds 13:
  ai-sdk-chat-transport, ai-chat-sandbox-and-ctx, chat-agent-*,
  chat-customagent-session-binding-and-stop-fixes,
  chat-reconnect-isstreaming-optional, chat-run-pat-renewal,
  chat-store-primitive, chat-transport-session-renew-plus-preload,
  drop-legacy-chat-stream-constants, dry-sloths-divide,
  trigger-chat-transport-watch-mode.
- sessions-primitive.md (core + sdk patch) — folds 3: session-primitive,
  session-sdk-toolkit, session-trigger-config-extra-fields.
- agent-skills.md (sdk + core + build + cli patch) — folds 2:
  chat-agent-skills-phase-1, skills-runtime-subpath.
- ai-tool-helpers.md (sdk patch) — folds 2: ai-tool-execute-helper,
  ai-tool-toolset-typing.
- mock-chat-agent-test-harness.md (sdk + core patch) — folds 3:
  mock-chat-agent-test-harness, mock-task-context-test-infra,
  mock-chat-agent-setup-locals.
- mcp-agent-chat-sessions.md (cli patch) — kept standalone.
- add-is-replay-context.md (core patch) — kept standalone (general task feature).
- truncate-error-stacks.md (core patch) — kept standalone (general infra).

Bumps preserved (chat-agent stays minor on sdk; everything else patch).
Auto-named "dry-sloths-divide" got merged into chat-agent and dropped.
This commit is contained in:
Eric Allam
2026-05-01 10:33:28 +01:00
parent 9ca81dd942
commit 88096fc3fd
26 changed files with 126 additions and 212 deletions
+18
View File
@@ -0,0 +1,18 @@
---
"@trigger.dev/sdk": patch
"@trigger.dev/core": patch
"@trigger.dev/build": patch
"trigger.dev": patch
---
Agent Skills — developer-authored folders (`SKILL.md` + scripts/references/assets) bundled into the deploy image automatically and discovered by the chat agent via progressive disclosure. Built on the [AI SDK cookbook pattern](https://ai-sdk.dev/cookbook/guides/agent-skills) — portable across providers.
**SDK:**
- `skills.define({ id, path })` registers a skill with the resource catalog; the Trigger.dev CLI bundles the folder into `/app/.trigger/skills/{id}/` automatically — no `trigger.config.ts` changes, no build extension.
- `SkillHandle.local()` reads the bundled `SKILL.md` at runtime, parses frontmatter, returns a `ResolvedSkill`.
- `chat.skills.set([...])` stores resolved skills for the current run.
- `chat.toStreamTextOptions()` auto-injects the skills preamble into the system prompt and merges three tools — `loadSkill`, `readFile`, `bash` — scoped per-skill with path-traversal guards and output caps (64 KB stdout/stderr, 1 MB `readFile`). `bash` runs with `cwd` = skill directory; the turn's abort signal propagates.
- `@trigger.dev/sdk/ai/skills-runtime` subpath — the `bash` + `readFile` runtime primitives (backed by `node:child_process` + `node:fs/promises`) live here, not in `@trigger.dev/sdk/ai`. Fixes client-bundle build errors (`UnhandledSchemeError: Reading from "node:child_process"…`) that hit Next.js + Webpack when a browser page imports types from `@trigger.dev/sdk/ai` (for example `ChatUiMessage` via a shared tools file). The chat-agent factory loads the runtime lazily via a computed-string dynamic import, so server workers still get full skill support without any caller changes.
This is the SDK + CLI layer only — no backend, no dashboard overrides yet. Dashboard-editable `SKILL.md` text and override flow are on the roadmap; `skill.resolve()` currently throws.
-6
View File
@@ -1,6 +0,0 @@
---
"@trigger.dev/sdk": patch
---
Add `TaskRunContext` (`ctx`) to all `chat.task` lifecycle events, `CompactedEvent`, and `ChatTaskRunPayload`. Export `TaskRunContext` from `@trigger.dev/sdk`.
-42
View File
@@ -1,42 +0,0 @@
---
"@trigger.dev/sdk": minor
---
Add AI SDK chat transport integration via two new subpath exports:
**`@trigger.dev/sdk/chat`** (frontend, browser-safe):
- `TriggerChatTransport` — custom `ChatTransport` for the AI SDK's `useChat` hook that runs chat completions as durable Trigger.dev tasks
- `createChatTransport()` — factory function
```tsx
import { useChat } from "@ai-sdk/react";
import { TriggerChatTransport } from "@trigger.dev/sdk/chat";
const { messages, sendMessage } = useChat({
transport: new TriggerChatTransport({
task: "my-chat-task",
accessToken,
}),
});
```
**`@trigger.dev/sdk/ai`** (backend, extends existing `ai.tool`/`ai.currentToolOptions`):
- `chatTask()` — pre-typed task wrapper with auto-pipe support
- `pipeChat()` — pipe a `StreamTextResult` or stream to the frontend
- `CHAT_STREAM_KEY` — the default stream key constant
- `ChatTaskPayload` type
```ts
import { chatTask } from "@trigger.dev/sdk/ai";
import { streamText, convertToModelMessages } from "ai";
export const myChatTask = chatTask({
id: "my-chat-task",
run: async ({ messages }) => {
return streamText({
model: openai("gpt-4o"),
messages: convertToModelMessages(messages),
});
},
});
```
-5
View File
@@ -1,5 +0,0 @@
---
"@trigger.dev/sdk": patch
---
Add `ai.toolExecute(task)` so you can pass Trigger's subtask/metadata wiring as the `execute` handler to AI SDK `tool()` while defining `description` and `inputSchema` yourself. Refactors `ai.tool()` to share the same internal handler.
+8
View File
@@ -0,0 +1,8 @@
---
"@trigger.dev/sdk": patch
---
AI SDK `tool()` helpers for Trigger subtasks:
- `ai.toolExecute(task)` — pass Trigger's subtask/metadata wiring as the `execute` handler to AI SDK `tool()` while you define `description` and `inputSchema` yourself. `ai.tool()` is now refactored to share the same internal handler.
- `ai.tool(task)` (`toolFromTask`) aligns with AI SDK `ToolSet`: Zod-backed tasks use static `tool()`; returns are asserted as `Tool & ToolSet[string]`. Minimum `ai` devDependency raised to `^6.0.116` so emitted types resolve the same `ToolSet` as apps on AI SDK 6.0.x — avoids cross-version `ToolSet` mismatches in monorepos.
-6
View File
@@ -1,6 +0,0 @@
---
"@trigger.dev/sdk": patch
---
Align `ai.tool()` (`toolFromTask`) with the AI SDK `ToolSet` shape: Zod-backed tasks use static `tool()`; returns are asserted as `Tool & ToolSet[string]`. Raise the SDK's minimum `ai` devDependency to `^6.0.116` so emitted types resolve the same `ToolSet` as apps on AI SDK 6.0.x (avoids cross-version `ToolSet` mismatches in monorepos).
@@ -1,5 +0,0 @@
---
"@trigger.dev/sdk": patch
---
Include `"action"` in the `ChatTaskPayload.trigger` union. `run()` is invoked with `trigger: "action"` after `onAction` processes a typed action, but the type previously omitted it. Users can now cleanly short-circuit the LLM call for actions that don't need a response (e.g. user-initiated compaction): `if (trigger === "action") return;`.
-5
View File
@@ -1,5 +0,0 @@
---
"@trigger.dev/sdk": patch
---
Add `chat.endRun()` — exits the run after the current turn completes, without the upgrade-required signal that `chat.requestUpgrade()` sends. Use when an agent finishes its work on its own terms (one-shot responses, goal achieved, budget exhausted) instead of waiting idle for the next user message. Call from `run()`, `chat.defer()`, `onBeforeTurnComplete`, or `onTurnComplete`.
-5
View File
@@ -1,5 +0,0 @@
---
"@trigger.dev/sdk": patch
---
Expose `finishReason` on `TurnCompleteEvent` and `BeforeTurnCompleteEvent`. Surfaces the AI SDK's `FinishReason` (`"stop" | "tool-calls" | "length" | ...`) so hooks can distinguish a normal turn end from one paused on a pending tool call (HITL flows like `ask_user`). Undefined for manual `pipeChat()` or aborted streams.
-16
View File
@@ -1,16 +0,0 @@
---
"@trigger.dev/sdk": patch
"@trigger.dev/core": patch
"@trigger.dev/build": patch
"trigger.dev": patch
---
Add agent skills — developer-authored folders (`SKILL.md` + scripts/references/assets) bundled into the deploy image automatically, discovered by the chat agent via progressive disclosure. Built on the [AI SDK cookbook pattern](https://ai-sdk.dev/cookbook/guides/agent-skills) — portable across providers.
**New:**
- `skills.define({ id, path })` registers a skill with the resource catalog; the Trigger.dev CLI bundles the folder into `/app/.trigger/skills/{id}/` automatically — no `trigger.config.ts` changes, no build extension.
- `SkillHandle.local()` reads the bundled `SKILL.md` at runtime, parses frontmatter, returns a `ResolvedSkill`.
- `chat.skills.set([...])` stores resolved skills for the current run.
- `chat.toStreamTextOptions()` auto-injects the skills preamble into the system prompt and merges three tools — `loadSkill`, `readFile`, `bash` — scoped per-skill with path-traversal guards and output caps (64 KB stdout/stderr, 1 MB `readFile`). `bash` runs with `cwd` = skill directory; the turn's abort signal propagates.
Phase 1 is SDK + CLI only — no backend, no dashboard overrides. Dashboard-editable `SKILL.md` text lands in Phase 2 (`skill.resolve()` currently throws).
+66
View File
@@ -0,0 +1,66 @@
---
"@trigger.dev/sdk": minor
"@trigger.dev/core": patch
---
`chat.agent` — durable AI chat as Trigger.dev tasks, with frontend wiring for the AI SDK's `useChat` hook. Built on top of the new Sessions primitive (separate changeset).
## SDK
**`@trigger.dev/sdk/ai`** (backend):
- `chat.agent({ id, run, ... })` — durable agent with full lifecycle hooks (`onPreload`, `onChatStart`, `onTurnStart`, `onBeforeTurnComplete`, `onTurnComplete`, `onCompacted`, `onValidateMessages`, `onAction`, `hydrateMessages`, `hydrateStore`). Auto-pipes a returned `streamText` result to the frontend.
- `chat.customAgent({ id, run })` — minimal protocol-level escape hatch; same session binding as `chat.agent`.
- `chat.withUIMessage<TUIMessage>().agent({...})` — generic-typed agent for custom `UIMessage` subtypes (typed `data-*` parts, tool maps, etc.). Ships `InferChatUIMessage`, generic `ChatUIMessageStreamOptions`, generic compaction + pending-message event types. `usePendingMessages` accepts a UI-message type parameter; `InferChatUIMessage` re-exported from `@trigger.dev/sdk/chat/react`.
- `chat.pipe(stream)` — pipe a `StreamTextResult` or stream from anywhere inside the agent.
- `chat.endRun()` — exit the run after the current turn completes, without the upgrade-required signal that `chat.requestUpgrade()` sends. Use for one-shot responses, agent-finished-its-work, or budget-exhausted exits.
- `chat.store` — typed, bidirectional shared data slot. `set` / `patch` (RFC 6902) / `get` / `onChange`; per-run scoped. Emits `store-snapshot` / `store-delta` chunks on the chat output stream. `hydrateStore` config for restore-on-continuation; `incomingStore` wire field for client-set data at turn start.
- `chat.sessionId` — getter for the friendlyId (`session_*`) of the run's backing Session. Throws outside chat.agent / chat.customAgent.
- `TaskRunContext` (`ctx`) on every lifecycle event, `CompactedEvent`, and `ChatTaskRunPayload`. `TaskRunContext` re-exported from `@trigger.dev/sdk`.
- `finishReason` on `TurnCompleteEvent` and `BeforeTurnCompleteEvent` — surfaces AI SDK's `FinishReason` (`"stop" | "tool-calls" | "length" | ...`) so hooks can distinguish a normal end from a paused-on-tool-call HITL flow. Undefined for manual `pipeChat()` or aborted streams.
- `ChatTaskPayload.trigger` includes `"action"`. Actions short-circuit the LLM call cleanly: `if (trigger === "action") return;`.
```ts
import { chat } from "@trigger.dev/sdk/ai";
import { streamText } from "ai";
import { openai } from "@ai-sdk/openai";
export const myChat = chat.agent({
id: "my-chat",
run: async ({ messages, signal }) =>
streamText({ model: openai("gpt-4o"), messages, abortSignal: signal }),
});
```
**`@trigger.dev/sdk/chat`** (frontend / browser):
- `TriggerChatTransport``ChatTransport` for `useChat`. Backed by Sessions: posts to `session.in/append`, subscribes to `session.out` SSE.
- `watch: true` option — read-only observation of an existing run. Keeps the internal stream open across `trigger:turn-complete` markers so a single `useChat` / `resumeStream` subscription observes every turn of a long-lived agent. Useful for dashboard viewers / debug UIs. Default `false` preserves interactive behavior.
- `RenewRunAccessTokenParams` includes the durable `sessionId` alongside `chatId` + `runId`. Renew handlers should mint with `read:sessions:{sessionId}` + `write:sessions:{sessionId}` scopes; renewing without session scopes throws the transport into a 401 loop on the first append after expiry.
- Run-scoped PAT renewal (`renewRunAccessToken`); fail fast on 401/403 for SSE without retry backoff. `isTriggerRealtimeAuthError` exported for auth-error detection.
- `transport.preload(chatId)` no longer calls `apiClient.createSession` from the browser — the server action returns `sessionId` in its result, matching how `sendMessages` already worked. Browser deployments using the `triggerTask` callback path therefore no longer need `write:sessions` on any browser-side token.
- `reconnectToStream` no longer requires callers to persist an `isStreaming` flag in `ChatSession` state — the short-circuit only triggers on explicit `isStreaming === false`.
**`@trigger.dev/sdk/chat/react`**:
- `useTriggerChatTransport({ task, accessToken, ... })` — memoized hook wrapping `TriggerChatTransport` for `useChat`.
## chat.agent fixes folded in
- `chat.customAgent` now binds the session handle (previously only `chat.agent` set up the per-run `SessionHandle`, so any custom agent that called `chat.messages.*`, `chat.stream.*`, `chat.createSession`, or `chat.createStopSignal` threw `chat.agent session handle is not initialized`). `chat.customAgent` now wraps the user's `run` and opens the session via `payload.sessionId ?? payload.chatId` before invoking it.
- Stop mid-stream no longer hangs the turn loop. The AI SDK's `runResult.totalUsage` promise can stay unresolved indefinitely on aborted Anthropic streams; the await is now raced against a 2s timeout so a stuck `totalUsage` falls through to a non-fatal "usage unknown" path and the turn finalizes correctly.
## Cleanup
The pre-Sessions chat stream-ID constants are gone:
- `CHAT_STREAM_KEY`, `CHAT_MESSAGES_STREAM_ID`, `CHAT_STOP_STREAM_ID` are no longer exported from `@trigger.dev/sdk/ai` or `@trigger.dev/core/v3/chat-client`.
- `packages/trigger-sdk/src/v3/chat-constants.ts` deleted.
- The labels still contain the same string values — they're now opaque breadcrumbs rather than user-consumable constants. Behavior and telemetry attrs unchanged.
These constants only mattered before chat.agent moved onto the Session primitive. Customers who referenced them externally should migrate to `sessions.open(sessionId).out.writer(...)` / `sessions.open(sessionId).in.on(...)` — same primitives, now session-keyed.
## Core
- New `chat.store` chunk types and `applyChatStorePatch` helper exported from `@trigger.dev/core/v3/chat-client`.
- `RenewRunAccessTokenParams` payload extended with `sessionId`.
@@ -1,9 +0,0 @@
---
"@trigger.dev/sdk": patch
---
Three chat.agent fixes surfaced by smoke-testing the Sessions migration:
- **`chat.customAgent` now binds the session handle.** Previously only `chat.agent` set up the per-run `SessionHandle` in run-locals, so any custom agent that called `chat.messages.*`, `chat.stream.*`, `chat.createSession`, or `chat.createStopSignal` threw `chat.agent session handle is not initialized`. `chat.customAgent` now wraps the user's `run` function and opens the session via `payload.sessionId ?? payload.chatId` before invoking it, matching `chat.agent`'s behavior.
- **Stop mid-stream no longer hangs the turn loop.** When the user aborts a turn, the AI SDK's `runResult.totalUsage` promise can stay unresolved indefinitely on Anthropic streams, blocking `onTurnComplete` / `writeTurnComplete` / the next-message wait. The await is now raced against a 2s timeout (mirroring the existing `onFinishPromise` race), so a stuck `totalUsage` falls through to a non-fatal "usage unknown" path and the turn finalizes correctly.
- **New `chat.sessionId` getter.** Returns the friendlyId (`session_*`) of the run's backing Session. Useful in `onPreload` / `onChatStart` / `onTurnComplete` for persisting the session id alongside `runId` so reloads can resume the same conversation. Throws if called outside a chat.agent / chat.customAgent run.
@@ -1,5 +0,0 @@
---
"@trigger.dev/sdk": patch
---
`TriggerChatTransport.reconnectToStream` no longer requires callers to persist an `isStreaming` flag in `ChatSession` state. Previously, any falsy `isStreaming` (including `undefined` when the flag was dropped from persistence) short-circuited reconnect to `null` and left the UI hanging on incomplete streams. Now the short-circuit only triggers on an explicit `isStreaming === false`, so callers can drop the flag entirely and let the server decide via the session's own `.out` tail. Existing callers that still persist `isStreaming` are unaffected.
-6
View File
@@ -1,6 +0,0 @@
---
"@trigger.dev/core": patch
"@trigger.dev/sdk": patch
---
Add run-scoped PAT renewal for chat transport (`renewRunAccessToken`), fail fast on 401/403 for SSE without retry backoff, and export `isTriggerRealtimeAuthError` for auth-error detection.
-21
View File
@@ -1,21 +0,0 @@
---
"@trigger.dev/sdk": patch
"@trigger.dev/core": patch
---
Add `chat.store` — a typed, bidirectional shared data slot on `chat.agent`. Agent-side foundation for TRI-8602. Independent of AG-UI — the same primitive will back the AG-UI `STATE_SNAPSHOT` / `STATE_DELTA` translator later.
**New on the agent:**
- `chat.store.set(value)` — replace, emits a `store-snapshot` chunk on the existing chat output stream.
- `chat.store.patch([...])` — RFC 6902 JSON Patch, emits a `store-delta` chunk.
- `chat.store.get()` — read the current value (scoped to the run).
- `chat.store.onChange((value, ops) => ...)` — subscribe to changes.
- `hydrateStore?: (event) => value` config on `chat.agent` — mirrors `hydrateMessages`; restore the store after a continuation from your own persistence layer.
- `ChatTaskWirePayload.incomingStore` — optional wire field applied at turn start before `run()` fires (last-write-wins over `hydrateStore`).
**New in core:**
- `store-snapshot` / `store-delta` chunk types and `applyChatStorePatch` helper exported from `@trigger.dev/core/v3/chat-client`.
The store lives in memory for the lifetime of the run and is persisted by the existing chat output stream plus the `hydrateStore` hook across continuations — no new infrastructure.
Client-side pieces (transport `getStore` / `setStore` / `applyStorePatch` / listeners, `AgentChat` accessors, `useChatStore` React hook, reference demo, docs) land in a follow-up.
@@ -1,8 +0,0 @@
---
"@trigger.dev/sdk": patch
---
`TriggerChatTransport` fixes for session-scoped auth and end-to-end UI smoke parity:
- `RenewRunAccessTokenParams` now includes the durable `sessionId` alongside `chatId` + `runId`. Server-side renew handlers should mint the renewed PAT with `read:sessions:{sessionId}` + `write:sessions:{sessionId}` scopes (in addition to the existing run scopes) so it keeps authenticating against the session `.in` append + `.out` subscribe endpoints. Renewing without session scopes sends the transport into a 401 loop on the first append after expiry.
- `transport.preload(chatId)` on the `triggerTask` callback path no longer calls `apiClient.createSession` from the browser. The server action (e.g. `chat.createTriggerAction`) creates the session with its secret key and returns the `sessionId` in its result, matching how `sendMessages` already worked. Browser deployments that use the `triggerTask` callback path therefore no longer need `write:sessions` on any browser-side token.
@@ -1,11 +0,0 @@
---
"@trigger.dev/sdk": patch
"@trigger.dev/core": patch
---
Drop the pre-Sessions chat stream-ID constants from the public surface:
- `CHAT_STREAM_KEY`, `CHAT_MESSAGES_STREAM_ID`, `CHAT_STOP_STREAM_ID` are no longer exported from `@trigger.dev/sdk/ai` or `@trigger.dev/core/v3/chat-client`. Deletes `packages/trigger-sdk/src/v3/chat-constants.ts`.
- The `chat.stream.id` / `chat.messages.id` / `chat.stopSignal.id` labels still contain the same string values (`"chat"` / `"chat-messages"` / `"chat-stop"`) — now inlined as opaque breadcrumbs rather than user-consumable constants. Behavior and telemetry attrs are unchanged.
These constants only mattered before the chat.agent I/O moved onto the Session primitive — the SDK no longer writes to run-scoped `streams.writer(CHAT_STREAM_KEY, …)` / `streams.input(CHAT_*_STREAM_ID)` at all. Customers who still referenced them externally should migrate to `sessions.open(sessionId).out.writer(...)` / `sessions.open(sessionId).in.on(...)` — same primitives, now session-keyed.
-5
View File
@@ -1,5 +0,0 @@
---
"@trigger.dev/sdk": patch
---
Add `chat.withUIMessage<TUIMessage>()` for typed AI SDK `UIMessage` in chat task hooks, optional factory `streamOptions` merged with `uiMessageStreamOptions`, and `InferChatUIMessage` helper. Generic `ChatUIMessageStreamOptions`, compaction, and pending-message event types. `usePendingMessages` accepts a UI message type parameter; re-export `InferChatUIMessage` from `@trigger.dev/sdk/chat/react`.
@@ -1,6 +0,0 @@
---
"@trigger.dev/sdk": patch
"@trigger.dev/core": patch
---
Add `setupLocals` option to `mockChatAgent` for dependency injection in tests. Pre-seed `locals` (database clients, service stubs) before the agent's `run()` starts, so hooks read the test instance via `locals.get()` without leaking through untrusted `clientData`. Also exposes `drivers.locals.set()` on `runInMockTaskContext`.
+12 -2
View File
@@ -3,6 +3,16 @@
"@trigger.dev/core": patch
---
Add `mockChatAgent` test harness at `@trigger.dev/sdk/ai/test` for unit-testing `chat.agent` definitions offline. Drives a real agent's turn loop without network or task runtime: send messages, actions, and stop signals via driver methods, inspect captured output chunks, and verify hooks fire. Pairs with `MockLanguageModelV3` from `ai/test` for model mocking.
Offline test harness for `chat.agent` — drive a real agent's turn loop in-process, no network, no task runtime. Pairs with `MockLanguageModelV3` from `ai/test` for model mocking.
Also adds `TestRunMetadataManager` to `@trigger.dev/core/v3/test` (in-memory metadata manager used by the harness), and exposes an `onWrite` hook on `TestRealtimeStreamsManager` so harnesses can react to stream writes without polling.
**`@trigger.dev/sdk/ai/test`:**
- `mockChatAgent(agent, options)` — drives a chat.agent definition end-to-end. Send messages, actions, and stop signals via driver methods; inspect captured output chunks; verify hooks fire.
- `setupLocals` option — pre-seed `locals` (database clients, service stubs) before the agent's `run()` starts, so hooks read the test instance via `locals.get()` without leaking through untrusted `clientData`.
**`@trigger.dev/core/v3/test`:**
- `runInMockTaskContext(fn, options)` — broader test harness for any task code. Installs in-memory managers for `locals`, `lifecycleHooks`, `runtime`, `inputStreams`, and `realtimeStreams`, plus a mock `TaskContext`. Drivers send data into input streams and inspect chunks written to output streams.
- `TestRunMetadataManager` — in-memory metadata manager used by the harness.
- `TestRealtimeStreamsManager.onWrite` hook — react to stream writes without polling.
- `drivers.locals.set()` exposed for direct DI.
@@ -1,5 +0,0 @@
---
"@trigger.dev/core": patch
---
Add `runInMockTaskContext` test harness at `@trigger.dev/core/v3/test` for unit-testing task code offline. Installs in-memory managers for `locals`, `lifecycleHooks`, `runtime`, `inputStreams`, and `realtimeStreams`, plus a mock `TaskContext`, so tasks can be driven end-to-end without hitting the Trigger.dev runtime. Provides drivers to send data into input streams and inspect chunks written to output streams.
-11
View File
@@ -1,11 +0,0 @@
---
"@trigger.dev/core": patch
"@trigger.dev/sdk": patch
---
Extend `SessionHandle` with two asymmetric channels mirroring the run-scoped streams primitives:
- `.in` (`SessionInputChannel`) mirrors `streams.input``on` / `once` / `peek` / `wait` / `waitWithIdleTimeout` for the task to consume, `send` for external clients to produce. `.wait` / `.waitWithIdleTimeout` suspend the run on a session-stream waitpoint; the run resumes when a record lands on `.in`.
- `.out` (`SessionOutputChannel`) mirrors `streams.define``append` / `pipe` / `writer` for the task to produce records (all route through direct-to-S2 for uniform parsed-object serialization), plus `read` for external SSE subscribers.
Adds the `sessionStreams` global + `StandardSessionStreamManager` (SSE-backed tail + buffer keyed on `{sessionId, io}`, registered in dev/managed run workers), `SessionStreamInstance` for direct-to-S2 piping, and `ApiClient.createSessionStreamWaitpoint` wiring.
@@ -1,5 +0,0 @@
---
"@trigger.dev/core": patch
---
Extend `SessionTriggerConfig` with three optional fields previously missing from the schema: `maxDuration` (per-run wall-clock cap, seconds), `lockToVersion` (pin every run to a specific worker version), and `region` (geographic scheduling). Each forwards to the matching field on `TaskRunOptions` when the run is triggered. Existing sessions without these fields are unaffected.
+22
View File
@@ -0,0 +1,22 @@
---
"@trigger.dev/core": patch
"@trigger.dev/sdk": patch
---
Sessions — durable, task-bound, bidirectional channel pair that outlives any single run. Foundation for `chat.agent` (separate changeset) and any other "one identifier, many runs over time" workflow.
A `Session` row is keyed on `(env, externalId)` (idempotent upsert), task-bound (`taskIdentifier` + `triggerConfig` are required), and owns its current run via `currentRunId` + `currentRunVersion` (optimistic claim). Three trigger paths: session create, append-time probe (a new run is triggered if the previous one has terminated), and `end-and-continue` for in-task version handoffs.
## SDK
- `SessionHandle` with two asymmetric channels mirroring run-scoped streams:
- `.in` (`SessionInputChannel`) mirrors `streams.input``on` / `once` / `peek` / `wait` / `waitWithIdleTimeout` for the task to consume, `send` for external clients to produce. `.wait` / `.waitWithIdleTimeout` suspend the run on a session-stream waitpoint; the run resumes when a record lands on `.in`.
- `.out` (`SessionOutputChannel`) mirrors `streams.define``append` / `pipe` / `writer` for the task to produce records (all route through direct-to-S2 for uniform parsed-object serialization), plus `read` for external SSE subscribers.
- `sessionStreams` global + `StandardSessionStreamManager` (SSE-backed tail + buffer keyed on `{sessionId, io}`, registered in dev/managed run workers).
- `SessionStreamInstance` for direct-to-S2 piping; `ApiClient.createSessionStreamWaitpoint` wiring.
## Core
- `SessionId` friendly-ID generator and Session schemas, exported from `@trigger.dev/core/v3/isomorphic` alongside `RunId`, `BatchId`, etc.
- `CreateSessionStreamWaitpoint` request/response schemas alongside the main Session CRUD.
- `SessionTriggerConfig` schema: `basePayload`, `machine`, `queue`, `tags`, `maxAttempts`, `idleTimeoutInSeconds`, plus `maxDuration` (per-run wall-clock cap, seconds), `lockToVersion` (pin every run to a specific worker version), and `region` (geographic scheduling). Each forwards to the matching field on `TaskRunOptions` when the run is triggered.
-5
View File
@@ -1,5 +0,0 @@
---
"@trigger.dev/sdk": patch
---
Split the skill-runtime primitives (`bash` + `readFile` tool implementations, backed by `node:child_process` + `node:fs/promises`) out of `@trigger.dev/sdk/ai` into a new `@trigger.dev/sdk/ai/skills-runtime` subpath. Fixes client-bundle build errors (`UnhandledSchemeError: Reading from "node:child_process"…`) that hit Next.js + Webpack when a browser page imports types from `@trigger.dev/sdk/ai` (for example `ChatUiMessage` via a shared tools file). The chat-agent factory now loads the runtime lazily via a computed-string dynamic import, so server workers still get full skill support without any caller changes.
@@ -1,23 +0,0 @@
---
"@trigger.dev/sdk": patch
---
Add `watch` option to `TriggerChatTransport` for read-only observation of an existing chat run.
When set to `true`, the transport keeps its internal `ReadableStream` open across `trigger:turn-complete` control chunks instead of closing it after each turn. This lets a single `useChat` / `resumeStream` subscription observe every turn of a long-lived agent run — useful for dashboard viewers or debug UIs that only want to watch an existing conversation as it unfolds, rather than drive it.
```tsx
const transport = new TriggerChatTransport({
task: "my-chat-task",
accessToken: runScopedPat,
watch: true,
sessions: {
[chatId]: { runId, publicAccessToken: runScopedPat },
},
});
const { messages, resumeStream } = useChat({ id: chatId, transport });
useEffect(() => { resumeStream(); }, [resumeStream]);
```
Non-watch transports are unaffected — the default remains `false` and existing behavior (close on turn-complete so `useChat` can flip to `"ready"` between turns) is preserved for interactive playground-style flows.