run() is invoked with trigger: "action" after onAction processes a
typed action, but the type previously omitted it. Adding it lets
users cleanly short-circuit the LLM call for actions that don't
need a response (e.g. user-initiated compaction):
if (trigger === "action") return;
Exit the loop 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. Callable from run(), chat.defer(),
onBeforeTurnComplete, or onTurnComplete.
Resolves TRI-8391.
Surface the AI SDK's FinishReason on TurnCompleteEvent and
BeforeTurnCompleteEvent. Gives hooks a clean signal for distinguishing
a normal turn end from one paused on a pending tool call (HITL flows
like ask_user). Undefined for manual pipeChat() or aborted streams.
Drives a chat.agent definition through real turns offline — send
messages, actions, and stop signals; inspect captured chunks; assert
on hook order. Pre-seed dependencies via setupLocals so hooks read
test instances (DB clients, stubs) via locals.get() instead of
leaking through untrusted clientData.
Adds ai-chat reference tests exercising the harness across basic
flow, onValidateMessages, hydrateMessages, and actions.
In-memory managers for locals, lifecycle hooks, runtime, input streams,
and realtime streams, plus a mock TaskContext. Lets task code be driven
end-to-end without hitting the Trigger.dev runtime — send data into
input streams, inspect chunks written to output streams, and pre-seed
locals for dependency injection.
Add isStreaming flag to session state — set true when streaming starts,
false on turn-complete. reconnectToStream returns null immediately when
isStreaming is false, so resume: true is safe to pass unconditionally.
Backend-controlled message history via hydrateMessages hook — loads from
DB on every turn, replacing the linear accumulator. Imperative chat.history
API (rollbackTo, remove, replace, slice) for modifying history from any
hook or run(). Custom actions via actionSchema + onAction — typed actions
sent through transport.sendAction() that wake the agent, modify state,
then trigger run(). Adds sendAction to both TriggerChatTransport and
AgentChat.
- 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
- 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
- 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
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