@trigger.dev/sdk 4.5.6 → 4.5.8
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/agentSkillsRuntime.js +17 -7
- package/dist/commonjs/v3/agentSkillsRuntime.js.map +1 -1
- package/dist/commonjs/v3/ai.d.ts +49 -8
- package/dist/commonjs/v3/ai.js +258 -42
- package/dist/commonjs/v3/ai.js.map +1 -1
- package/dist/commonjs/v3/aiAutoTelemetry.js +3 -3
- package/dist/commonjs/v3/aiAutoTelemetry.js.map +1 -1
- package/dist/commonjs/v3/auth.d.ts +7 -3
- package/dist/commonjs/v3/auth.js +68 -13
- package/dist/commonjs/v3/auth.js.map +1 -1
- package/dist/commonjs/v3/auth.test.d.ts +1 -0
- package/dist/commonjs/v3/auth.test.js +149 -0
- package/dist/commonjs/v3/auth.test.js.map +1 -0
- package/dist/commonjs/v3/createStartSessionAction.test.js +33 -0
- package/dist/commonjs/v3/createStartSessionAction.test.js.map +1 -1
- package/dist/commonjs/v3/index.js +17 -7
- package/dist/commonjs/v3/index.js.map +1 -1
- package/dist/commonjs/v3/runs.d.ts +15 -15
- package/dist/commonjs/v3/skill.js +17 -7
- package/dist/commonjs/v3/skill.js.map +1 -1
- package/dist/commonjs/v3/test/test-session-handle.js +20 -8
- package/dist/commonjs/v3/test/test-session-handle.js.map +1 -1
- package/dist/commonjs/v3/triggerClient.js +17 -7
- package/dist/commonjs/v3/triggerClient.js.map +1 -1
- package/dist/commonjs/v3/triggerClient.types.test.js +17 -7
- package/dist/commonjs/v3/triggerClient.types.test.js.map +1 -1
- package/dist/commonjs/version.js +1 -1
- package/dist/esm/v3/ai.d.ts +49 -8
- package/dist/esm/v3/ai.js +259 -43
- package/dist/esm/v3/ai.js.map +1 -1
- package/dist/esm/v3/aiAutoTelemetry.js +3 -3
- package/dist/esm/v3/aiAutoTelemetry.js.map +1 -1
- package/dist/esm/v3/auth.d.ts +7 -3
- package/dist/esm/v3/auth.js +69 -14
- package/dist/esm/v3/auth.js.map +1 -1
- package/dist/esm/v3/auth.test.d.ts +1 -0
- package/dist/esm/v3/auth.test.js +147 -0
- package/dist/esm/v3/auth.test.js.map +1 -0
- package/dist/esm/v3/createStartSessionAction.test.js +33 -0
- package/dist/esm/v3/createStartSessionAction.test.js.map +1 -1
- package/dist/esm/v3/test/test-session-handle.js +20 -8
- package/dist/esm/v3/test/test-session-handle.js.map +1 -1
- package/dist/esm/version.js +1 -1
- package/docs/ai-chat/changelog.mdx +2 -2
- package/docs/ai-chat/compaction.mdx +2 -2
- package/docs/ai-chat/custom-agents.mdx +15 -20
- package/docs/ai-chat/fast-starts.mdx +2 -2
- package/docs/ai-chat/pending-messages.mdx +6 -2
- package/docs/ai-chat/reference.mdx +2 -2
- package/package.json +3 -3
|
@@ -15,13 +15,23 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
|
|
|
15
15
|
}) : function(o, v) {
|
|
16
16
|
o["default"] = v;
|
|
17
17
|
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || function (
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
};
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
25
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
36
|
exports.readFileInSkill = readFileInSkill;
|
|
27
37
|
exports.runBashInSkill = runBashInSkill;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agentSkillsRuntime.js","sourceRoot":"","sources":["../../../src/v3/agentSkillsRuntime.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"agentSkillsRuntime.js","sourceRoot":"","sources":["../../../src/v3/agentSkillsRuntime.ts"],"names":[],"mappings":"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"}
|
package/dist/commonjs/v3/ai.d.ts
CHANGED
|
@@ -2456,34 +2456,75 @@ declare function createStopSignal(): {
|
|
|
2456
2456
|
* The `TriggerChatTransport` intercepts this to close the ReadableStream
|
|
2457
2457
|
* for the current turn. Call after piping the response stream.
|
|
2458
2458
|
*
|
|
2459
|
+
* Returns two resume cursors for the turn boundary, both saveable from the
|
|
2460
|
+
* task instead of round-tripping them back from the client:
|
|
2461
|
+
* - `lastEventId` — the turn-complete control record's seq_num on
|
|
2462
|
+
* `session.out`; where the next turn's output stream resumes.
|
|
2463
|
+
* - `sessionInEventId` — the committed-consume cursor on `session.in` as of
|
|
2464
|
+
* this turn-complete, letting a raw loop correlate the boundary with the
|
|
2465
|
+
* exact input record it acknowledged. Trigger owns input-cursor recovery,
|
|
2466
|
+
* so this is for correlation / out-of-sync detection, not required.
|
|
2467
|
+
*
|
|
2468
|
+
* Either is `undefined` when the corresponding cursor isn't available.
|
|
2469
|
+
*
|
|
2459
2470
|
* @example
|
|
2460
2471
|
* ```ts
|
|
2461
2472
|
* await chat.pipe(result);
|
|
2462
|
-
* await chat.writeTurnComplete();
|
|
2473
|
+
* const { lastEventId, sessionInEventId } = await chat.writeTurnComplete();
|
|
2474
|
+
* await db.chats.update(chatId, { lastEventId, sessionInEventId });
|
|
2463
2475
|
* ```
|
|
2464
2476
|
*/
|
|
2465
2477
|
declare function chatWriteTurnComplete(options?: {
|
|
2466
2478
|
publicAccessToken?: string;
|
|
2467
|
-
}): Promise<
|
|
2479
|
+
}): Promise<{
|
|
2480
|
+
lastEventId?: string;
|
|
2481
|
+
sessionInEventId?: string;
|
|
2482
|
+
}>;
|
|
2483
|
+
/**
|
|
2484
|
+
* The outcome of a turn's stream, reported by {@link pipeChatAndCapture}.
|
|
2485
|
+
*
|
|
2486
|
+
* - `complete` — the stream finished on its own.
|
|
2487
|
+
* - `aborted` — the stream was stopped via the `signal` (user stop / cancel).
|
|
2488
|
+
* - `error` — the stream threw; `error` carries what was thrown.
|
|
2489
|
+
*
|
|
2490
|
+
* `message` holds whatever the assistant produced and is present for every
|
|
2491
|
+
* status — including `aborted` and `error` — as long as any output streamed
|
|
2492
|
+
* before the stop or failure, so partial responses are never lost.
|
|
2493
|
+
*/
|
|
2494
|
+
export type PipeAndCaptureResult = {
|
|
2495
|
+
/** The captured assistant message, or `undefined` if nothing streamed. */
|
|
2496
|
+
message: UIMessage | undefined;
|
|
2497
|
+
/** Coarse outcome of the stream. */
|
|
2498
|
+
status: "complete" | "aborted" | "error";
|
|
2499
|
+
/** The AI SDK finish reason, when the stream reported one. */
|
|
2500
|
+
finishReason?: FinishReason;
|
|
2501
|
+
/** What the stream threw, present only when `status === "error"`. */
|
|
2502
|
+
error?: unknown;
|
|
2503
|
+
};
|
|
2468
2504
|
/**
|
|
2469
2505
|
* Pipe a `StreamTextResult` (or similar) to the chat stream and capture
|
|
2470
2506
|
* the assistant's response message via `onFinish`.
|
|
2471
2507
|
*
|
|
2472
2508
|
* Combines `toUIMessageStream()` + `onFinish` callback + `chat.pipe()`.
|
|
2473
|
-
*
|
|
2509
|
+
* Never throws on a stopped or failed stream: it returns a
|
|
2510
|
+
* {@link PipeAndCaptureResult} whose `message` holds any partial output
|
|
2511
|
+
* captured before the stop/failure, alongside a typed `status` (and `error`
|
|
2512
|
+
* on failure). Save the partial after a stop or error without separate
|
|
2513
|
+
* capture logic.
|
|
2474
2514
|
*
|
|
2475
2515
|
* @example
|
|
2476
2516
|
* ```ts
|
|
2477
2517
|
* const result = streamText({ model, messages, abortSignal: signal });
|
|
2478
|
-
* const
|
|
2479
|
-
* if (
|
|
2518
|
+
* const { message, status, error } = await chat.pipeAndCapture(result, { signal });
|
|
2519
|
+
* if (message) conversation.addResponse(message);
|
|
2520
|
+
* if (status === "error") logger.error("turn failed", { error });
|
|
2480
2521
|
* ```
|
|
2481
2522
|
*/
|
|
2482
2523
|
declare function pipeChatAndCapture(source: UIMessageStreamable, options?: {
|
|
2483
2524
|
signal?: AbortSignal;
|
|
2484
2525
|
spanName?: string;
|
|
2485
2526
|
originalMessages?: UIMessage[];
|
|
2486
|
-
}): Promise<
|
|
2527
|
+
}): Promise<PipeAndCaptureResult>;
|
|
2487
2528
|
/**
|
|
2488
2529
|
* Accumulates conversation messages across turns.
|
|
2489
2530
|
*
|
|
@@ -2497,8 +2538,8 @@ declare function pipeChatAndCapture(source: UIMessageStreamable, options?: {
|
|
|
2497
2538
|
* for (let turn = 0; turn < 100; turn++) {
|
|
2498
2539
|
* const messages = await conversation.addIncoming(payload.messages, payload.trigger, turn);
|
|
2499
2540
|
* const result = streamText({ model, messages });
|
|
2500
|
-
* const
|
|
2501
|
-
* if (
|
|
2541
|
+
* const { message } = await chat.pipeAndCapture(result);
|
|
2542
|
+
* if (message) await conversation.addResponse(message);
|
|
2502
2543
|
* }
|
|
2503
2544
|
* ```
|
|
2504
2545
|
*/
|
package/dist/commonjs/v3/ai.js
CHANGED
|
@@ -3636,6 +3636,9 @@ function chatAgent(options) {
|
|
|
3636
3636
|
// Declared here so the finally can detach it — a handler leaked past
|
|
3637
3637
|
// its turn duplicates every mid-stream message into the shared buffer.
|
|
3638
3638
|
let turnMsgSub;
|
|
3639
|
+
let capturedPartialResponse;
|
|
3640
|
+
let responseCommitted = false;
|
|
3641
|
+
const turnBufferedChunks = [];
|
|
3639
3642
|
try {
|
|
3640
3643
|
// Extract turn-level context before entering the span. Slim
|
|
3641
3644
|
// wire: at most one delta message per record. `headStartMessages`
|
|
@@ -4313,11 +4316,12 @@ function chatAgent(options) {
|
|
|
4313
4316
|
generateMessageId: resolvedOptions.generateMessageId ?? ai_runtime_js_1.generateId,
|
|
4314
4317
|
onFinish: ({ responseMessage, finishReason, }) => {
|
|
4315
4318
|
capturedResponseMessage = responseMessage;
|
|
4319
|
+
capturedPartialResponse = responseMessage;
|
|
4316
4320
|
capturedFinishReason = finishReason;
|
|
4317
4321
|
resolveOnFinish();
|
|
4318
4322
|
},
|
|
4319
4323
|
});
|
|
4320
|
-
await pipeChat(uiStream, {
|
|
4324
|
+
await pipeChat(tapUIMessageChunks(uiStream, turnBufferedChunks), {
|
|
4321
4325
|
signal: combinedSignal,
|
|
4322
4326
|
spanName: "stream response",
|
|
4323
4327
|
});
|
|
@@ -4511,6 +4515,11 @@ function chatAgent(options) {
|
|
|
4511
4515
|
locals_js_1.locals.set(chatCurrentUIMessagesKey, accumulatedUIMessages);
|
|
4512
4516
|
}
|
|
4513
4517
|
}
|
|
4518
|
+
if (capturedResponseMessage) {
|
|
4519
|
+
responseCommitted = true;
|
|
4520
|
+
capturedPartialResponse = capturedResponseMessage;
|
|
4521
|
+
turnBufferedChunks.length = 0;
|
|
4522
|
+
}
|
|
4514
4523
|
if (runSignal.aborted)
|
|
4515
4524
|
return "exit";
|
|
4516
4525
|
// Await deferred background work (e.g. DB writes from onTurnStart)
|
|
@@ -4701,6 +4710,7 @@ function chatAgent(options) {
|
|
|
4701
4710
|
parts: [...(msg.parts ?? []), ...lateParts],
|
|
4702
4711
|
};
|
|
4703
4712
|
capturedResponseMessage = accumulatedUIMessages[idx];
|
|
4713
|
+
capturedPartialResponse = capturedResponseMessage;
|
|
4704
4714
|
turnCompleteEvent.responseMessage = capturedResponseMessage;
|
|
4705
4715
|
turnCompleteEvent.uiMessages = accumulatedUIMessages;
|
|
4706
4716
|
}
|
|
@@ -4943,10 +4953,65 @@ function chatAgent(options) {
|
|
|
4943
4953
|
!accumulatedUIMessages.some((m) => m.id === erroredWireMessage.id)
|
|
4944
4954
|
? [...accumulatedUIMessages, erroredWireMessage]
|
|
4945
4955
|
: accumulatedUIMessages;
|
|
4946
|
-
|
|
4947
|
-
|
|
4948
|
-
|
|
4949
|
-
|
|
4956
|
+
let partialResponse = capturedPartialResponse ??
|
|
4957
|
+
(await assemblePartialFromChunks(turnBufferedChunks));
|
|
4958
|
+
if (partialResponse) {
|
|
4959
|
+
partialResponse = cleanupAbortedParts(partialResponse);
|
|
4960
|
+
}
|
|
4961
|
+
let partialIdx = partialResponse?.id
|
|
4962
|
+
? erroredUIMessages.findIndex((m) => m.id === partialResponse.id)
|
|
4963
|
+
: -1;
|
|
4964
|
+
if (partialResponse && capturedPartialResponse === undefined && partialIdx !== -1) {
|
|
4965
|
+
partialResponse = undefined;
|
|
4966
|
+
partialIdx = -1;
|
|
4967
|
+
}
|
|
4968
|
+
if (partialResponse && !partialResponse.id) {
|
|
4969
|
+
partialResponse = { ...partialResponse, id: (0, ai_runtime_js_1.generateId)() };
|
|
4970
|
+
}
|
|
4971
|
+
if (partialResponse && !responseCommitted) {
|
|
4972
|
+
const queuedParts = locals_js_1.locals.get(chatResponsePartsKey);
|
|
4973
|
+
if (queuedParts && queuedParts.length > 0) {
|
|
4974
|
+
partialResponse = {
|
|
4975
|
+
...partialResponse,
|
|
4976
|
+
parts: [...partialResponse.parts, ...queuedParts],
|
|
4977
|
+
};
|
|
4978
|
+
locals_js_1.locals.set(chatResponsePartsKey, []);
|
|
4979
|
+
}
|
|
4980
|
+
}
|
|
4981
|
+
const includePartial = partialResponse != null && !responseCommitted;
|
|
4982
|
+
let erroredUIMessagesWithPartial = !includePartial
|
|
4983
|
+
? erroredUIMessages
|
|
4984
|
+
: partialIdx === -1
|
|
4985
|
+
? [...erroredUIMessages, partialResponse]
|
|
4986
|
+
: erroredUIMessages.map((m, i) => i === partialIdx ? partialResponse : m);
|
|
4987
|
+
let erroredNewUIMessages = erroredWireMessage ? [erroredWireMessage] : [];
|
|
4988
|
+
if (includePartial) {
|
|
4989
|
+
erroredNewUIMessages.push(partialResponse);
|
|
4990
|
+
}
|
|
4991
|
+
let erroredNewModelMessages = [];
|
|
4992
|
+
if (!responseCommitted) {
|
|
4993
|
+
try {
|
|
4994
|
+
if (erroredNewUIMessages.length > 0) {
|
|
4995
|
+
erroredNewModelMessages = await toModelMessages(erroredNewUIMessages.map((m) => stripProviderMetadata(m)));
|
|
4996
|
+
}
|
|
4997
|
+
if (erroredUIMessagesWithPartial !== accumulatedUIMessages) {
|
|
4998
|
+
if (partialIdx === -1) {
|
|
4999
|
+
const appended = erroredUIMessagesWithPartial.slice(accumulatedUIMessages.length);
|
|
5000
|
+
accumulatedMessages.push(...(await toModelMessages(appended.map((m) => stripProviderMetadata(m)))));
|
|
5001
|
+
}
|
|
5002
|
+
else {
|
|
5003
|
+
accumulatedMessages = await toModelMessages(erroredUIMessagesWithPartial);
|
|
5004
|
+
}
|
|
5005
|
+
accumulatedUIMessages = erroredUIMessagesWithPartial;
|
|
5006
|
+
locals_js_1.locals.set(chatCurrentUIMessagesKey, accumulatedUIMessages);
|
|
5007
|
+
}
|
|
5008
|
+
}
|
|
5009
|
+
catch {
|
|
5010
|
+
erroredNewModelMessages = [];
|
|
5011
|
+
erroredUIMessagesWithPartial = erroredUIMessages;
|
|
5012
|
+
erroredNewUIMessages = erroredWireMessage ? [erroredWireMessage] : [];
|
|
5013
|
+
}
|
|
5014
|
+
}
|
|
4950
5015
|
if (onTurnComplete) {
|
|
4951
5016
|
try {
|
|
4952
5017
|
await tracer_js_1.tracer.startActiveSpan("onTurnComplete()", async () => {
|
|
@@ -4954,11 +5019,11 @@ function chatAgent(options) {
|
|
|
4954
5019
|
ctx,
|
|
4955
5020
|
chatId: currentWirePayload.chatId,
|
|
4956
5021
|
messages: accumulatedMessages,
|
|
4957
|
-
uiMessages:
|
|
4958
|
-
newMessages:
|
|
4959
|
-
newUIMessages:
|
|
4960
|
-
responseMessage:
|
|
4961
|
-
rawResponseMessage:
|
|
5022
|
+
uiMessages: erroredUIMessagesWithPartial,
|
|
5023
|
+
newMessages: erroredNewModelMessages,
|
|
5024
|
+
newUIMessages: erroredNewUIMessages,
|
|
5025
|
+
responseMessage: partialResponse,
|
|
5026
|
+
rawResponseMessage: partialResponse,
|
|
4962
5027
|
turn,
|
|
4963
5028
|
runId: ctx.run.id,
|
|
4964
5029
|
chatAccessToken: "",
|
|
@@ -5002,7 +5067,7 @@ function chatAgent(options) {
|
|
|
5002
5067
|
await writeChatSnapshot(sessionIdForSnapshot, {
|
|
5003
5068
|
version: 1,
|
|
5004
5069
|
savedAt: Date.now(),
|
|
5005
|
-
messages:
|
|
5070
|
+
messages: erroredUIMessagesWithPartial,
|
|
5006
5071
|
lastOutEventId: errorTurnCompleteResult?.lastEventId,
|
|
5007
5072
|
lastInEventId: errorSnapshotInCursor !== undefined ? String(errorSnapshotInCursor) : undefined,
|
|
5008
5073
|
});
|
|
@@ -5612,31 +5677,110 @@ function createStopSignal() {
|
|
|
5612
5677
|
* The `TriggerChatTransport` intercepts this to close the ReadableStream
|
|
5613
5678
|
* for the current turn. Call after piping the response stream.
|
|
5614
5679
|
*
|
|
5680
|
+
* Returns two resume cursors for the turn boundary, both saveable from the
|
|
5681
|
+
* task instead of round-tripping them back from the client:
|
|
5682
|
+
* - `lastEventId` — the turn-complete control record's seq_num on
|
|
5683
|
+
* `session.out`; where the next turn's output stream resumes.
|
|
5684
|
+
* - `sessionInEventId` — the committed-consume cursor on `session.in` as of
|
|
5685
|
+
* this turn-complete, letting a raw loop correlate the boundary with the
|
|
5686
|
+
* exact input record it acknowledged. Trigger owns input-cursor recovery,
|
|
5687
|
+
* so this is for correlation / out-of-sync detection, not required.
|
|
5688
|
+
*
|
|
5689
|
+
* Either is `undefined` when the corresponding cursor isn't available.
|
|
5690
|
+
*
|
|
5615
5691
|
* @example
|
|
5616
5692
|
* ```ts
|
|
5617
5693
|
* await chat.pipe(result);
|
|
5618
|
-
* await chat.writeTurnComplete();
|
|
5694
|
+
* const { lastEventId, sessionInEventId } = await chat.writeTurnComplete();
|
|
5695
|
+
* await db.chats.update(chatId, { lastEventId, sessionInEventId });
|
|
5619
5696
|
* ```
|
|
5620
5697
|
*/
|
|
5621
5698
|
async function chatWriteTurnComplete(options) {
|
|
5622
|
-
await writeTurnCompleteChunk(undefined, options?.publicAccessToken);
|
|
5699
|
+
const result = await writeTurnCompleteChunk(undefined, options?.publicAccessToken);
|
|
5700
|
+
// Same cursor written to the `session-in-event-id` header inside
|
|
5701
|
+
// `writeTurnCompleteChunk`; surfaced here so the caller can persist it.
|
|
5702
|
+
const inCursor = getChatSession().in.lastDispatchedSeqNum();
|
|
5703
|
+
return {
|
|
5704
|
+
lastEventId: result?.lastEventId,
|
|
5705
|
+
...(inCursor !== undefined ? { sessionInEventId: String(inCursor) } : {}),
|
|
5706
|
+
};
|
|
5707
|
+
}
|
|
5708
|
+
/**
|
|
5709
|
+
* Pass every chunk through untouched while recording it in `buffer`. Handles
|
|
5710
|
+
* both the `AsyncIterable` and `ReadableStream` shapes `toUIMessageStream()`
|
|
5711
|
+
* can return, and propagates a source error to the consumer after buffering
|
|
5712
|
+
* whatever streamed first. See {@link pipeChatAndCapture} for why.
|
|
5713
|
+
*/
|
|
5714
|
+
function tapUIMessageChunks(source, buffer) {
|
|
5715
|
+
if (isReadableStream(source)) {
|
|
5716
|
+
return source.pipeThrough(new TransformStream({
|
|
5717
|
+
transform(chunk, controller) {
|
|
5718
|
+
buffer.push(chunk);
|
|
5719
|
+
controller.enqueue(chunk);
|
|
5720
|
+
},
|
|
5721
|
+
}));
|
|
5722
|
+
}
|
|
5723
|
+
return (async function* () {
|
|
5724
|
+
for await (const chunk of source) {
|
|
5725
|
+
buffer.push(chunk);
|
|
5726
|
+
yield chunk;
|
|
5727
|
+
}
|
|
5728
|
+
})();
|
|
5729
|
+
}
|
|
5730
|
+
/**
|
|
5731
|
+
* Reconstruct a partial assistant `UIMessage` from the raw chunks that
|
|
5732
|
+
* streamed before a failure — the fallback for {@link pipeChatAndCapture}
|
|
5733
|
+
* when a transport error abandons the stream before `onFinish` runs. Uses the
|
|
5734
|
+
* same `readUIMessageStream` reducer as the boot-time replay path. Returns
|
|
5735
|
+
* `undefined` if there's nothing to assemble or the reducer throws.
|
|
5736
|
+
*/
|
|
5737
|
+
async function assemblePartialFromChunks(chunks) {
|
|
5738
|
+
const relevant = chunks.filter((c) => {
|
|
5739
|
+
const type = c.type;
|
|
5740
|
+
return typeof type === "string" && !type.startsWith("trigger:");
|
|
5741
|
+
});
|
|
5742
|
+
if (relevant.length === 0)
|
|
5743
|
+
return undefined;
|
|
5744
|
+
try {
|
|
5745
|
+
const stream = new ReadableStream({
|
|
5746
|
+
start(controller) {
|
|
5747
|
+
for (const chunk of relevant)
|
|
5748
|
+
controller.enqueue(chunk);
|
|
5749
|
+
controller.close();
|
|
5750
|
+
},
|
|
5751
|
+
});
|
|
5752
|
+
let last;
|
|
5753
|
+
for await (const message of (0, ai_runtime_js_1.readUIMessageStream)({ stream })) {
|
|
5754
|
+
last = message;
|
|
5755
|
+
}
|
|
5756
|
+
return last;
|
|
5757
|
+
}
|
|
5758
|
+
catch {
|
|
5759
|
+
return undefined;
|
|
5760
|
+
}
|
|
5623
5761
|
}
|
|
5624
5762
|
/**
|
|
5625
5763
|
* Pipe a `StreamTextResult` (or similar) to the chat stream and capture
|
|
5626
5764
|
* the assistant's response message via `onFinish`.
|
|
5627
5765
|
*
|
|
5628
5766
|
* Combines `toUIMessageStream()` + `onFinish` callback + `chat.pipe()`.
|
|
5629
|
-
*
|
|
5767
|
+
* Never throws on a stopped or failed stream: it returns a
|
|
5768
|
+
* {@link PipeAndCaptureResult} whose `message` holds any partial output
|
|
5769
|
+
* captured before the stop/failure, alongside a typed `status` (and `error`
|
|
5770
|
+
* on failure). Save the partial after a stop or error without separate
|
|
5771
|
+
* capture logic.
|
|
5630
5772
|
*
|
|
5631
5773
|
* @example
|
|
5632
5774
|
* ```ts
|
|
5633
5775
|
* const result = streamText({ model, messages, abortSignal: signal });
|
|
5634
|
-
* const
|
|
5635
|
-
* if (
|
|
5776
|
+
* const { message, status, error } = await chat.pipeAndCapture(result, { signal });
|
|
5777
|
+
* if (message) conversation.addResponse(message);
|
|
5778
|
+
* if (status === "error") logger.error("turn failed", { error });
|
|
5636
5779
|
* ```
|
|
5637
5780
|
*/
|
|
5638
5781
|
async function pipeChatAndCapture(source, options) {
|
|
5639
5782
|
let captured;
|
|
5783
|
+
let capturedFinishReason;
|
|
5640
5784
|
let resolveOnFinish;
|
|
5641
5785
|
const onFinishPromise = new Promise((r) => {
|
|
5642
5786
|
resolveOnFinish = r;
|
|
@@ -5654,17 +5798,57 @@ async function pipeChatAndCapture(source, options) {
|
|
|
5654
5798
|
// the frontend replaces the partial message — wiping the
|
|
5655
5799
|
// pre-injection text from the UI and the captured response.
|
|
5656
5800
|
generateMessageId: resolvedOptions.generateMessageId ?? ai_runtime_js_1.generateId,
|
|
5657
|
-
onFinish: ({ responseMessage }) => {
|
|
5801
|
+
onFinish: ({ responseMessage, finishReason, }) => {
|
|
5658
5802
|
captured = responseMessage;
|
|
5803
|
+
capturedFinishReason = finishReason;
|
|
5659
5804
|
resolveOnFinish();
|
|
5660
5805
|
},
|
|
5661
5806
|
});
|
|
5662
|
-
|
|
5663
|
-
|
|
5664
|
-
|
|
5665
|
-
|
|
5666
|
-
|
|
5667
|
-
|
|
5807
|
+
// Buffer chunks as they flow to the pipe so a transport failure that
|
|
5808
|
+
// abandons the UI stream before `onFinish` fires — the one termination path
|
|
5809
|
+
// that skips `onFinish` — can still reconstruct the partial. This retains
|
|
5810
|
+
// chunk references only; the reassembly runs solely in the failure fallback
|
|
5811
|
+
// below, so the happy path pays nothing extra.
|
|
5812
|
+
const bufferedChunks = [];
|
|
5813
|
+
const tappedStream = tapUIMessageChunks(uiStream, bufferedChunks);
|
|
5814
|
+
let status = "complete";
|
|
5815
|
+
let error;
|
|
5816
|
+
try {
|
|
5817
|
+
await pipeChat(tappedStream, {
|
|
5818
|
+
signal: options?.signal,
|
|
5819
|
+
spanName: options?.spanName ?? "stream response",
|
|
5820
|
+
});
|
|
5821
|
+
// The pipe can drain cleanly on a stop — the source stream just ends
|
|
5822
|
+
// early — so classify by the signal rather than relying on a throw.
|
|
5823
|
+
if (options?.signal?.aborted) {
|
|
5824
|
+
status = "aborted";
|
|
5825
|
+
}
|
|
5826
|
+
}
|
|
5827
|
+
catch (err) {
|
|
5828
|
+
if ((err instanceof Error && err.name === "AbortError") || options?.signal?.aborted) {
|
|
5829
|
+
status = "aborted";
|
|
5830
|
+
}
|
|
5831
|
+
else {
|
|
5832
|
+
status = "error";
|
|
5833
|
+
error = err;
|
|
5834
|
+
}
|
|
5835
|
+
}
|
|
5836
|
+
// `onFinish` fires even on abort, carrying the partial — but a hard stop can
|
|
5837
|
+
// prevent it from firing at all, so race it against a timeout to avoid
|
|
5838
|
+
// hanging the caller. Mirrors chat.agent's capture path.
|
|
5839
|
+
await Promise.race([onFinishPromise, new Promise((r) => setTimeout(r, 2_000))]);
|
|
5840
|
+
// A transport failure can abandon the UI stream before `onFinish` fires, so
|
|
5841
|
+
// reconstruct the partial from the buffered chunks rather than losing output
|
|
5842
|
+
// that already streamed. Only runs when `onFinish` produced nothing.
|
|
5843
|
+
if (!captured && bufferedChunks.length > 0) {
|
|
5844
|
+
captured = await assemblePartialFromChunks(bufferedChunks);
|
|
5845
|
+
}
|
|
5846
|
+
return {
|
|
5847
|
+
message: captured,
|
|
5848
|
+
status,
|
|
5849
|
+
finishReason: capturedFinishReason,
|
|
5850
|
+
...(error !== undefined ? { error } : {}),
|
|
5851
|
+
};
|
|
5668
5852
|
}
|
|
5669
5853
|
/**
|
|
5670
5854
|
* Accumulates conversation messages across turns.
|
|
@@ -5679,8 +5863,8 @@ async function pipeChatAndCapture(source, options) {
|
|
|
5679
5863
|
* for (let turn = 0; turn < 100; turn++) {
|
|
5680
5864
|
* const messages = await conversation.addIncoming(payload.messages, payload.trigger, turn);
|
|
5681
5865
|
* const result = streamText({ model, messages });
|
|
5682
|
-
* const
|
|
5683
|
-
* if (
|
|
5866
|
+
* const { message } = await chat.pipeAndCapture(result);
|
|
5867
|
+
* if (message) await conversation.addResponse(message);
|
|
5684
5868
|
* }
|
|
5685
5869
|
* ```
|
|
5686
5870
|
*/
|
|
@@ -6174,7 +6358,7 @@ function createChatSession(payload, options) {
|
|
|
6174
6358
|
}
|
|
6175
6359
|
let response;
|
|
6176
6360
|
try {
|
|
6177
|
-
|
|
6361
|
+
const captured = await pipeChatAndCapture(source, {
|
|
6178
6362
|
signal: combinedSignal,
|
|
6179
6363
|
// On a non-final handover turn, thread the spliced partial so a
|
|
6180
6364
|
// resumed tool round's tool-output chunks merge into the
|
|
@@ -6183,20 +6367,27 @@ function createChatSession(payload, options) {
|
|
|
6183
6367
|
// fresh response into the prior assistant message).
|
|
6184
6368
|
...(handoverThisTurn ? { originalMessages: accumulator.uiMessages } : {}),
|
|
6185
6369
|
});
|
|
6186
|
-
|
|
6187
|
-
|
|
6188
|
-
|
|
6189
|
-
|
|
6190
|
-
|
|
6191
|
-
sessionMsgSub.off();
|
|
6192
|
-
await chatWriteTurnComplete();
|
|
6193
|
-
return undefined;
|
|
6194
|
-
}
|
|
6195
|
-
// Stop — fall through to accumulate partial response
|
|
6370
|
+
if (runSignal.aborted) {
|
|
6371
|
+
// Full cancel — don't accumulate
|
|
6372
|
+
sessionMsgSub.off();
|
|
6373
|
+
await chatWriteTurnComplete();
|
|
6374
|
+
return undefined;
|
|
6196
6375
|
}
|
|
6197
|
-
|
|
6198
|
-
|
|
6376
|
+
// Surface a genuine stream failure to the caller. A user stop
|
|
6377
|
+
// (status "aborted") falls through so the partial is accumulated.
|
|
6378
|
+
if (captured.status === "error") {
|
|
6379
|
+
if (captured.message) {
|
|
6380
|
+
const partial = cleanupAbortedParts(captured.message);
|
|
6381
|
+
const queuedParts = locals_js_1.locals.get(chatResponsePartsKey);
|
|
6382
|
+
if (queuedParts && queuedParts.length > 0) {
|
|
6383
|
+
partial.parts = [...(partial.parts ?? []), ...queuedParts];
|
|
6384
|
+
locals_js_1.locals.set(chatResponsePartsKey, []);
|
|
6385
|
+
}
|
|
6386
|
+
await accumulator.addResponse(partial);
|
|
6387
|
+
}
|
|
6388
|
+
throw captured.error;
|
|
6199
6389
|
}
|
|
6390
|
+
response = captured.message;
|
|
6200
6391
|
}
|
|
6201
6392
|
finally {
|
|
6202
6393
|
// Detach at stream end (like the agent loop): the steering queue
|
|
@@ -6738,24 +6929,49 @@ async function mintPublicTokenWithOverride(args) {
|
|
|
6738
6929
|
throw new Error("chat.createStartSessionAction: no API access token configured for JWT mint.");
|
|
6739
6930
|
}
|
|
6740
6931
|
const ctx = { endpoint: "auth", chatId: args.chatId };
|
|
6741
|
-
const
|
|
6932
|
+
const scopes = [`read:sessions:${args.chatId}`, `write:sessions:${args.chatId}`];
|
|
6933
|
+
const serverMint = (0, v3_1.isAdditionalApiKey)(accessToken);
|
|
6934
|
+
const endpoint = serverMint ? "/api/v1/auth/public-tokens" : "/api/v1/auth/jwt/claims";
|
|
6935
|
+
const url = `${resolveChatStartBaseURL("auth", args.chatId, args.baseURLOption)}${endpoint}`;
|
|
6742
6936
|
const init = {
|
|
6743
6937
|
method: "POST",
|
|
6744
6938
|
headers: overrideRequestHeaders(accessToken),
|
|
6939
|
+
...(serverMint
|
|
6940
|
+
? {
|
|
6941
|
+
body: JSON.stringify({
|
|
6942
|
+
scopes,
|
|
6943
|
+
expirationTime: args.expirationTime instanceof Date
|
|
6944
|
+
? Math.floor(args.expirationTime.getTime() / 1000)
|
|
6945
|
+
: args.expirationTime,
|
|
6946
|
+
}),
|
|
6947
|
+
}
|
|
6948
|
+
: {}),
|
|
6745
6949
|
};
|
|
6746
6950
|
const response = args.fetchOverride
|
|
6747
6951
|
? await args.fetchOverride(url, init, ctx)
|
|
6748
6952
|
: await fetch(url, init);
|
|
6749
6953
|
if (!response.ok) {
|
|
6954
|
+
// An additional API key cannot self-sign, so it must use the server mint
|
|
6955
|
+
// endpoint. On a server too old to expose it, explain the recovery path
|
|
6956
|
+
// instead of surfacing a bare 404 (mirrors auth.createServerPublicToken).
|
|
6957
|
+
if (serverMint && response.status === 404) {
|
|
6958
|
+
throw new Error("This additional API key cannot self-sign public tokens, and the server does not support public-token minting. Upgrade the server or use the root API key.");
|
|
6959
|
+
}
|
|
6750
6960
|
const text = await response.text().catch(() => "");
|
|
6751
6961
|
throw new Error(`auth.createPublicToken failed: ${response.status} ${text}`);
|
|
6752
6962
|
}
|
|
6753
|
-
const
|
|
6963
|
+
const responseBody = (await response.json());
|
|
6964
|
+
if (serverMint) {
|
|
6965
|
+
if (typeof responseBody.token !== "string") {
|
|
6966
|
+
throw new Error("auth.createPublicToken failed: server response did not include a token");
|
|
6967
|
+
}
|
|
6968
|
+
return responseBody.token;
|
|
6969
|
+
}
|
|
6754
6970
|
return (0, v3_1.generateJWT)({
|
|
6755
6971
|
secretKey: accessToken,
|
|
6756
6972
|
payload: {
|
|
6757
|
-
...
|
|
6758
|
-
scopes
|
|
6973
|
+
...responseBody,
|
|
6974
|
+
scopes,
|
|
6759
6975
|
},
|
|
6760
6976
|
expirationTime: args.expirationTime,
|
|
6761
6977
|
});
|