@trigger.dev/sdk 0.0.0-chat-prerelease-20260414141814 → 0.0.0-chat-prerelease-20260414181032
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commonjs/v3/ai.d.ts +8 -0
- package/dist/commonjs/v3/ai.js +135 -4
- package/dist/commonjs/v3/ai.js.map +1 -1
- package/dist/commonjs/version.js +1 -1
- package/dist/esm/v3/ai.d.ts +8 -0
- package/dist/esm/v3/ai.js +135 -4
- package/dist/esm/v3/ai.js.map +1 -1
- package/dist/esm/version.js +1 -1
- package/package.json +2 -2
package/dist/commonjs/v3/ai.d.ts
CHANGED
|
@@ -2104,6 +2104,14 @@ export declare const chat: {
|
|
|
2104
2104
|
inject: typeof injectBackgroundContext;
|
|
2105
2105
|
/** Typed chat output stream for writing custom chunks or piping from subtasks. */
|
|
2106
2106
|
stream: import("@trigger.dev/core/v3").RealtimeDefinedStream<UIMessageChunk>;
|
|
2107
|
+
/** Write data parts that persist to the response message. See {@link chatResponse}. */
|
|
2108
|
+
response: {
|
|
2109
|
+
/**
|
|
2110
|
+
* Write a single chunk. Non-transient data parts are accumulated into the
|
|
2111
|
+
* response message; everything else is stream-only.
|
|
2112
|
+
*/
|
|
2113
|
+
write(part: UIMessageChunk): void;
|
|
2114
|
+
};
|
|
2107
2115
|
/** Pre-built input stream for receiving messages from the transport. */
|
|
2108
2116
|
messages: import("@trigger.dev/core/v3").RealtimeDefinedInputStream<ChatTaskWirePayload<UIMessage<unknown, import("ai").UIDataTypes, import("ai").UITools>, unknown>>;
|
|
2109
2117
|
/** Create a managed stop signal wired to the stop input stream. See {@link createStopSignal}. */
|
package/dist/commonjs/v3/ai.js
CHANGED
|
@@ -243,6 +243,43 @@ exports.CHAT_STREAM_KEY = chat_constants_js_1.CHAT_STREAM_KEY;
|
|
|
243
243
|
* ```
|
|
244
244
|
*/
|
|
245
245
|
const chatStream = streams_js_1.streams.define({ id: chat_constants_js_1.CHAT_STREAM_KEY });
|
|
246
|
+
// ---------------------------------------------------------------------------
|
|
247
|
+
// chat.response — write data parts that persist to the response message
|
|
248
|
+
// ---------------------------------------------------------------------------
|
|
249
|
+
/**
|
|
250
|
+
* Write data parts that both stream to the frontend AND persist in
|
|
251
|
+
* `onTurnComplete`'s `responseMessage` and `uiMessages`.
|
|
252
|
+
*
|
|
253
|
+
* Non-transient data chunks (`type` starts with `data-`, no `transient: true`)
|
|
254
|
+
* are queued for accumulation into the assistant response message.
|
|
255
|
+
* Transient or non-data chunks are streamed only (same as `chat.stream`).
|
|
256
|
+
*
|
|
257
|
+
* @example
|
|
258
|
+
* ```ts
|
|
259
|
+
* // Persists to responseMessage.parts
|
|
260
|
+
* chat.response.write({ type: "data-handover", data: { context: summary } });
|
|
261
|
+
*
|
|
262
|
+
* // Transient — streams only, not in responseMessage
|
|
263
|
+
* chat.response.write({ type: "data-progress", data: { percent: 50 }, transient: true });
|
|
264
|
+
* ```
|
|
265
|
+
*/
|
|
266
|
+
const chatResponse = {
|
|
267
|
+
/**
|
|
268
|
+
* Write a single chunk. Non-transient data parts are accumulated into the
|
|
269
|
+
* response message; everything else is stream-only.
|
|
270
|
+
*/
|
|
271
|
+
write(part) {
|
|
272
|
+
queueResponsePart(part);
|
|
273
|
+
const { waitUntilComplete } = streams_js_1.streams.writer(exports.CHAT_STREAM_KEY, {
|
|
274
|
+
spanName: "chat.response.write",
|
|
275
|
+
collapsed: true,
|
|
276
|
+
execute: ({ write }) => {
|
|
277
|
+
write(part);
|
|
278
|
+
},
|
|
279
|
+
});
|
|
280
|
+
waitUntilComplete().catch(() => { });
|
|
281
|
+
},
|
|
282
|
+
};
|
|
246
283
|
/**
|
|
247
284
|
* Creates a lazy ChatWriter that only opens a realtime stream on first use.
|
|
248
285
|
* Call `flush()` after the callback returns to await stream completion.
|
|
@@ -274,6 +311,7 @@ function createLazyChatWriter() {
|
|
|
274
311
|
writer: {
|
|
275
312
|
write(part) {
|
|
276
313
|
ensureInitialized();
|
|
314
|
+
queueResponsePart(part);
|
|
277
315
|
writeImpl(part);
|
|
278
316
|
},
|
|
279
317
|
merge(stream) {
|
|
@@ -400,6 +438,30 @@ const chatPendingMessagesKey = locals_js_1.locals.create("chat.pendingMessages")
|
|
|
400
438
|
const chatSteeringQueueKey = locals_js_1.locals.create("chat.steeringQueue");
|
|
401
439
|
/** @internal — IDs of messages that were successfully injected via prepareStep */
|
|
402
440
|
const chatInjectedMessageIdsKey = locals_js_1.locals.create("chat.injectedMessageIds");
|
|
441
|
+
/** @internal — non-transient data parts queued via chat.response or writer.write() for accumulation into the response message */
|
|
442
|
+
const chatResponsePartsKey = locals_js_1.locals.create("chat.responseParts");
|
|
443
|
+
/**
|
|
444
|
+
* Check if a chunk is a non-transient data part that should persist to the response message.
|
|
445
|
+
* @internal
|
|
446
|
+
*/
|
|
447
|
+
function isNonTransientDataPart(part) {
|
|
448
|
+
if (typeof part !== "object" || part === null)
|
|
449
|
+
return false;
|
|
450
|
+
const p = part;
|
|
451
|
+
return typeof p.type === "string" && p.type.startsWith("data-") && p.transient !== true;
|
|
452
|
+
}
|
|
453
|
+
/**
|
|
454
|
+
* Queue a chunk for accumulation into the response message (if it's a non-transient data part).
|
|
455
|
+
* Called by `chat.response.write()` and `ChatWriter.write()`.
|
|
456
|
+
* @internal
|
|
457
|
+
*/
|
|
458
|
+
function queueResponsePart(part) {
|
|
459
|
+
if (!isNonTransientDataPart(part))
|
|
460
|
+
return;
|
|
461
|
+
const parts = locals_js_1.locals.get(chatResponsePartsKey) ?? [];
|
|
462
|
+
parts.push(part);
|
|
463
|
+
locals_js_1.locals.set(chatResponsePartsKey, parts);
|
|
464
|
+
}
|
|
403
465
|
/**
|
|
404
466
|
* Check that no tool calls are in-flight in a step's content.
|
|
405
467
|
* Used before compaction to avoid losing tool state mid-execution.
|
|
@@ -536,6 +598,7 @@ async function chatCompact(messages, steps, options) {
|
|
|
536
598
|
type: "data-compaction",
|
|
537
599
|
id: compactionId,
|
|
538
600
|
data: { status: "compacting", totalTokens },
|
|
601
|
+
transient: true,
|
|
539
602
|
});
|
|
540
603
|
// Generate summary
|
|
541
604
|
summary = await options.summarize(messages);
|
|
@@ -576,6 +639,7 @@ async function chatCompact(messages, steps, options) {
|
|
|
576
639
|
type: "data-compaction",
|
|
577
640
|
id: compactionId,
|
|
578
641
|
data: { status: "complete", totalTokens },
|
|
642
|
+
transient: true,
|
|
579
643
|
});
|
|
580
644
|
write({ type: "finish-step" });
|
|
581
645
|
},
|
|
@@ -1174,6 +1238,7 @@ function chatAgent(options) {
|
|
|
1174
1238
|
locals_js_1.locals.set(chatDeferKey, new Set());
|
|
1175
1239
|
locals_js_1.locals.set(chatCompactionStateKey, undefined);
|
|
1176
1240
|
locals_js_1.locals.set(chatSteeringQueueKey, []);
|
|
1241
|
+
locals_js_1.locals.set(chatResponsePartsKey, []);
|
|
1177
1242
|
// NOTE: chatBackgroundQueueKey is NOT reset here — messages injected
|
|
1178
1243
|
// by deferred work from the previous turn's onTurnComplete need to
|
|
1179
1244
|
// survive into the next turn. The queue is drained before run().
|
|
@@ -1592,6 +1657,15 @@ function chatAgent(options) {
|
|
|
1592
1657
|
if (!capturedResponseMessage.id) {
|
|
1593
1658
|
capturedResponseMessage = { ...capturedResponseMessage, id: (0, ai_1.generateId)() };
|
|
1594
1659
|
}
|
|
1660
|
+
// Append any non-transient data parts queued via chat.response or writer.write()
|
|
1661
|
+
const queuedParts = locals_js_1.locals.get(chatResponsePartsKey);
|
|
1662
|
+
if (queuedParts && queuedParts.length > 0) {
|
|
1663
|
+
capturedResponseMessage = {
|
|
1664
|
+
...capturedResponseMessage,
|
|
1665
|
+
parts: [...capturedResponseMessage.parts, ...queuedParts],
|
|
1666
|
+
};
|
|
1667
|
+
locals_js_1.locals.set(chatResponsePartsKey, []);
|
|
1668
|
+
}
|
|
1595
1669
|
accumulatedUIMessages.push(capturedResponseMessage);
|
|
1596
1670
|
turnNewUIMessages.push(capturedResponseMessage);
|
|
1597
1671
|
try {
|
|
@@ -1605,10 +1679,21 @@ function chatAgent(options) {
|
|
|
1605
1679
|
// Conversion failed — skip accumulation for this turn
|
|
1606
1680
|
}
|
|
1607
1681
|
}
|
|
1608
|
-
//
|
|
1609
|
-
//
|
|
1610
|
-
|
|
1611
|
-
|
|
1682
|
+
// If there's no captured response (manual pipe mode) but there are
|
|
1683
|
+
// queued data parts, create a minimal response message to hold them.
|
|
1684
|
+
if (!capturedResponseMessage) {
|
|
1685
|
+
const remainingParts = locals_js_1.locals.get(chatResponsePartsKey);
|
|
1686
|
+
if (remainingParts && remainingParts.length > 0) {
|
|
1687
|
+
capturedResponseMessage = {
|
|
1688
|
+
id: (0, ai_1.generateId)(),
|
|
1689
|
+
role: "assistant",
|
|
1690
|
+
parts: [...remainingParts],
|
|
1691
|
+
};
|
|
1692
|
+
locals_js_1.locals.set(chatResponsePartsKey, []);
|
|
1693
|
+
accumulatedUIMessages.push(capturedResponseMessage);
|
|
1694
|
+
turnNewUIMessages.push(capturedResponseMessage);
|
|
1695
|
+
}
|
|
1696
|
+
}
|
|
1612
1697
|
if (runSignal.aborted)
|
|
1613
1698
|
return "exit";
|
|
1614
1699
|
// Await deferred background work (e.g. DB writes from onTurnStart)
|
|
@@ -1650,6 +1735,7 @@ function chatAgent(options) {
|
|
|
1650
1735
|
type: "data-compaction",
|
|
1651
1736
|
id: compactionId,
|
|
1652
1737
|
data: { status: "compacting", totalTokens: turnUsage.totalTokens },
|
|
1738
|
+
transient: true,
|
|
1653
1739
|
});
|
|
1654
1740
|
const summary = await outerCompaction.summarize({
|
|
1655
1741
|
messages: accumulatedMessages,
|
|
@@ -1711,6 +1797,7 @@ function chatAgent(options) {
|
|
|
1711
1797
|
type: "data-compaction",
|
|
1712
1798
|
id: compactionId,
|
|
1713
1799
|
data: { status: "complete", totalTokens: turnUsage.totalTokens },
|
|
1800
|
+
transient: true,
|
|
1714
1801
|
});
|
|
1715
1802
|
},
|
|
1716
1803
|
});
|
|
@@ -1784,6 +1871,22 @@ function chatAgent(options) {
|
|
|
1784
1871
|
},
|
|
1785
1872
|
});
|
|
1786
1873
|
}
|
|
1874
|
+
// Drain any late response parts added during onBeforeTurnComplete
|
|
1875
|
+
const lateParts = locals_js_1.locals.get(chatResponsePartsKey);
|
|
1876
|
+
if (lateParts && lateParts.length > 0 && capturedResponseMessage) {
|
|
1877
|
+
const idx = accumulatedUIMessages.findIndex((m) => m.id === capturedResponseMessage.id);
|
|
1878
|
+
if (idx !== -1) {
|
|
1879
|
+
const msg = accumulatedUIMessages[idx];
|
|
1880
|
+
accumulatedUIMessages[idx] = {
|
|
1881
|
+
...msg,
|
|
1882
|
+
parts: [...(msg.parts ?? []), ...lateParts],
|
|
1883
|
+
};
|
|
1884
|
+
capturedResponseMessage = accumulatedUIMessages[idx];
|
|
1885
|
+
turnCompleteEvent.responseMessage = capturedResponseMessage;
|
|
1886
|
+
turnCompleteEvent.uiMessages = accumulatedUIMessages;
|
|
1887
|
+
}
|
|
1888
|
+
locals_js_1.locals.set(chatResponsePartsKey, []);
|
|
1889
|
+
}
|
|
1787
1890
|
// Write turn-complete control chunk — closes the frontend stream.
|
|
1788
1891
|
const turnCompleteResult = await writeTurnCompleteChunk(currentWirePayload.chatId, turnAccessToken);
|
|
1789
1892
|
// Fire onTurnComplete — stream is closed, use for persistence.
|
|
@@ -2791,6 +2894,8 @@ function createChatSession(payload, options) {
|
|
|
2791
2894
|
}
|
|
2792
2895
|
// Reset stop signal for this turn
|
|
2793
2896
|
stop.reset();
|
|
2897
|
+
// Reset per-turn state
|
|
2898
|
+
locals_js_1.locals.set(chatResponsePartsKey, []);
|
|
2794
2899
|
// Set up steering queue and pending messages config in locals
|
|
2795
2900
|
// so toStreamTextOptions() auto-injects prepareStep for steering
|
|
2796
2901
|
const turnSteeringQueue = [];
|
|
@@ -2887,8 +2992,26 @@ function createChatSession(payload, options) {
|
|
|
2887
2992
|
const cleaned = stop.signal.aborted && !runSignal.aborted
|
|
2888
2993
|
? cleanupAbortedParts(response)
|
|
2889
2994
|
: response;
|
|
2995
|
+
// Append any non-transient data parts queued via chat.response or writer.write()
|
|
2996
|
+
const queuedParts = locals_js_1.locals.get(chatResponsePartsKey);
|
|
2997
|
+
if (queuedParts && queuedParts.length > 0) {
|
|
2998
|
+
cleaned.parts = [...(cleaned.parts ?? []), ...queuedParts];
|
|
2999
|
+
locals_js_1.locals.set(chatResponsePartsKey, []);
|
|
3000
|
+
}
|
|
2890
3001
|
await accumulator.addResponse(cleaned);
|
|
2891
3002
|
}
|
|
3003
|
+
else {
|
|
3004
|
+
// No response (manual pipe mode) but there are queued data parts
|
|
3005
|
+
const queuedParts = locals_js_1.locals.get(chatResponsePartsKey);
|
|
3006
|
+
if (queuedParts && queuedParts.length > 0) {
|
|
3007
|
+
await accumulator.addResponse({
|
|
3008
|
+
id: (0, ai_1.generateId)(),
|
|
3009
|
+
role: "assistant",
|
|
3010
|
+
parts: queuedParts,
|
|
3011
|
+
});
|
|
3012
|
+
locals_js_1.locals.set(chatResponsePartsKey, []);
|
|
3013
|
+
}
|
|
3014
|
+
}
|
|
2892
3015
|
// Capture token usage from the streamText result
|
|
2893
3016
|
let turnUsage;
|
|
2894
3017
|
if (typeof source.totalUsage?.then === "function") {
|
|
@@ -2955,6 +3078,12 @@ function createChatSession(payload, options) {
|
|
|
2955
3078
|
return response;
|
|
2956
3079
|
},
|
|
2957
3080
|
async addResponse(response) {
|
|
3081
|
+
// Append any non-transient data parts queued via chat.response or writer.write()
|
|
3082
|
+
const queuedParts = locals_js_1.locals.get(chatResponsePartsKey);
|
|
3083
|
+
if (queuedParts && queuedParts.length > 0) {
|
|
3084
|
+
response = { ...response, parts: [...(response.parts ?? []), ...queuedParts] };
|
|
3085
|
+
locals_js_1.locals.set(chatResponsePartsKey, []);
|
|
3086
|
+
}
|
|
2958
3087
|
await accumulator.addResponse(response);
|
|
2959
3088
|
},
|
|
2960
3089
|
async done() {
|
|
@@ -3257,6 +3386,8 @@ exports.chat = {
|
|
|
3257
3386
|
inject: injectBackgroundContext,
|
|
3258
3387
|
/** Typed chat output stream for writing custom chunks or piping from subtasks. */
|
|
3259
3388
|
stream: chatStream,
|
|
3389
|
+
/** Write data parts that persist to the response message. See {@link chatResponse}. */
|
|
3390
|
+
response: chatResponse,
|
|
3260
3391
|
/** Pre-built input stream for receiving messages from the transport. */
|
|
3261
3392
|
messages: messagesInput,
|
|
3262
3393
|
/** Create a managed stop signal wired to the stop input stream. See {@link createStopSignal}. */
|