Skip to content

Commit d69fcf4

Browse files
committed
feat(chat): add per-action settlement callback
1 parent 7e92a02 commit d69fcf4

4 files changed

Lines changed: 554 additions & 3 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@trigger.dev/sdk": patch
3+
---
4+
5+
Add an optional `onSettled` callback to `TriggerChatTransport.sendAction()` so callers can confirm that their action's input was processed, independently of whether the response stream closes.

docs/ai-chat/reference.mdx

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -836,10 +836,28 @@ See [Stop generation](/ai-chat/frontend#stop-generation) for full details.
836836

837837
Send a custom action to the agent, outside `useChat`. Actions wake the agent from suspension and fire `onAction`. An action that returns `chat.turn()` is followed by a turn; its answer arrives on the returned stream, which the caller must read. From a `useChat` app, send actions as requests instead (`sendMessage(undefined, { body: { action } })` or the `useChatActions` hook) so `useChat` renders the answer.
838838

839-
```ts
840-
transport.sendAction(chatId: string, action: unknown): Promise<ReadableStream<UIMessageChunk>>
839+
```typescript
840+
transport.sendAction(
841+
chatId: string,
842+
action: unknown,
843+
options?: ChatActionOptions
844+
): Promise<ReadableStream<UIMessageChunk>>
841845
```
842846

847+
`ChatActionOptions` and `ChatActionSettlement` are exported from `@trigger.dev/sdk/chat`.
848+
849+
| Option | Type | Description |
850+
| --- | --- | --- |
851+
| `abortSignal` | `AbortSignal` | Cancel the action's response subscription and send a stop signal for an outstanding turn. |
852+
| `metadata` | `Record<string, unknown>` | Per-action metadata merged over the transport's `clientData`. |
853+
| `onSettled` | `(settlement: ChatActionSettlement) => void` | Called at most once when this subscription accepts a turn-complete record confirming the action's input was processed. |
854+
855+
`onSettled` receives `{ inputSeq, sessionInEventId, lastEventId? }`: the action's input append sequence, the committed input cursor, and the output cursor of the completion record. It runs before the returned stream closes, or continues in watch mode. Settlement confirms input processing, not application-level success; read the response chunks for the action's result. Synchronous callback exceptions do not interrupt the stream.
856+
857+
<Note>
858+
The callback does not run after cancellation, stream closure without a matching completion, missing or invalid cursors, or an error because a previous stop caused the action's output to be discarded. In that last case, the action's own completion can arrive while its response stream still throws an output-lost error. A missing callback does not prove the action was unprocessed: reconcile persisted state or make the action idempotent before retrying.
859+
</Note>
860+
843861
For managed `chat.agent()` tasks, the action payload is validated against the agent's `actionSchema` on the backend. Raw `chat.customAgent()` tasks receive it as `unknown` and must validate it themselves.
844862

845863
```tsx

0 commit comments

Comments
 (0)