@trigger.dev/sdk 4.5.1 → 4.5.3
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-shared.d.ts +3 -127
- package/dist/commonjs/v3/ai-shared.js.map +1 -1
- package/dist/commonjs/v3/ai.js +66 -22
- package/dist/commonjs/v3/ai.js.map +1 -1
- package/dist/commonjs/v3/chat-react.d.ts +1 -0
- package/dist/commonjs/v3/chat-react.js +4 -1
- package/dist/commonjs/v3/chat-react.js.map +1 -1
- package/dist/commonjs/v3/chat.d.ts +204 -1
- package/dist/commonjs/v3/chat.js +203 -19
- package/dist/commonjs/v3/chat.js.map +1 -1
- package/dist/commonjs/v3/index.d.ts +1 -1
- package/dist/commonjs/v3/index.js.map +1 -1
- package/dist/commonjs/v3/runs-bulk.test.d.ts +1 -0
- package/dist/commonjs/v3/runs-bulk.test.js +141 -0
- package/dist/commonjs/v3/runs-bulk.test.js.map +1 -0
- package/dist/commonjs/v3/runs.d.ts +23 -6
- package/dist/commonjs/v3/runs.js +87 -0
- package/dist/commonjs/v3/runs.js.map +1 -1
- package/dist/commonjs/v3/sessions.js +5 -2
- package/dist/commonjs/v3/sessions.js.map +1 -1
- package/dist/commonjs/v3/shared.d.ts +2 -2
- package/dist/commonjs/v3/shared.js +79 -4
- package/dist/commonjs/v3/shared.js.map +1 -1
- package/dist/commonjs/v3/shared.test.js +37 -0
- package/dist/commonjs/v3/shared.test.js.map +1 -1
- package/dist/commonjs/version.js +1 -1
- package/dist/esm/v3/ai-shared.d.ts +3 -127
- package/dist/esm/v3/ai-shared.js.map +1 -1
- package/dist/esm/v3/ai.js +66 -22
- package/dist/esm/v3/ai.js.map +1 -1
- package/dist/esm/v3/chat-react.d.ts +1 -0
- package/dist/esm/v3/chat-react.js +4 -1
- package/dist/esm/v3/chat-react.js.map +1 -1
- package/dist/esm/v3/chat.d.ts +204 -1
- package/dist/esm/v3/chat.js +204 -20
- package/dist/esm/v3/chat.js.map +1 -1
- package/dist/esm/v3/index.d.ts +1 -1
- package/dist/esm/v3/index.js.map +1 -1
- package/dist/esm/v3/runs-bulk.test.d.ts +1 -0
- package/dist/esm/v3/runs-bulk.test.js +139 -0
- package/dist/esm/v3/runs-bulk.test.js.map +1 -0
- package/dist/esm/v3/runs.d.ts +18 -1
- package/dist/esm/v3/runs.js +87 -0
- package/dist/esm/v3/runs.js.map +1 -1
- package/dist/esm/v3/sessions.js +5 -2
- package/dist/esm/v3/sessions.js.map +1 -1
- package/dist/esm/v3/shared.d.ts +2 -2
- package/dist/esm/v3/shared.js +79 -5
- package/dist/esm/v3/shared.js.map +1 -1
- package/dist/esm/v3/shared.test.js +38 -1
- package/dist/esm/v3/shared.test.js.map +1 -1
- package/dist/esm/version.js +1 -1
- package/docs/ai-chat/frontend.mdx +46 -0
- package/docs/ai-chat/pending-messages.mdx +3 -1
- package/docs/ai-chat/reference.mdx +20 -0
- package/docs/billing-limits.mdx +73 -0
- package/docs/github-repo.mdx +1 -1
- package/docs/how-to-reduce-your-spend.mdx +1 -14
- package/docs/limits.mdx +5 -0
- package/docs/quick-start.mdx +1 -1
- package/docs/self-hosting/docker.mdx +24 -1
- package/docs/self-hosting/env/webapp.mdx +6 -1
- package/docs/self-hosting/kubernetes.mdx +26 -0
- package/docs/self-hosting/overview.mdx +4 -1
- package/docs/self-hosting/security.mdx +50 -0
- package/docs/troubleshooting.mdx +4 -0
- package/package.json +2 -2
- package/docs/open-source-self-hosting.mdx +0 -541
|
@@ -15,138 +15,14 @@
|
|
|
15
15
|
* import from `ai.ts`.
|
|
16
16
|
*/
|
|
17
17
|
import type { Task, AnyTask } from "@trigger.dev/core/v3";
|
|
18
|
-
import type { InferUITools,
|
|
18
|
+
import type { InferUITools, ToolSet, UIDataTypes, UIMessage } from "ai";
|
|
19
19
|
/**
|
|
20
20
|
* Message-part `type` value for the pending-message data part the agent
|
|
21
21
|
* injects when a follow-up message arrives mid-turn.
|
|
22
22
|
*/
|
|
23
23
|
export declare const PENDING_MESSAGE_INJECTED_TYPE: "data-pending-message-injected";
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
* Uses `metadata` to match the AI SDK's `ChatRequestOptions` field name.
|
|
27
|
-
*
|
|
28
|
-
* Slim wire: at most ONE message per record. The agent runtime
|
|
29
|
-
* reconstructs prior history at run boot from a durable S3 snapshot +
|
|
30
|
-
* `session.out` replay (or `hydrateMessages` if registered). The wire is
|
|
31
|
-
* delta-only — see plan `vivid-humming-bonbon.md`.
|
|
32
|
-
*/
|
|
33
|
-
export type ChatTaskWirePayload<TMessage extends UIMessage = UIMessage, TMetadata = unknown> = {
|
|
34
|
-
/**
|
|
35
|
-
* The single message being delivered on this trigger. Set for:
|
|
36
|
-
* - `submit-message`: the new user message OR a tool-approval-responded
|
|
37
|
-
* assistant message (with `state: "approval-responded"` tool parts).
|
|
38
|
-
* - `regenerate-message`: omitted (the agent slices its own history).
|
|
39
|
-
* - `preload` / `close` / `action`: omitted.
|
|
40
|
-
* - `handover-prepare`: omitted (use `headStartMessages` instead).
|
|
41
|
-
*/
|
|
42
|
-
message?: TMessage;
|
|
43
|
-
/**
|
|
44
|
-
* Bespoke escape hatch for `chat.headStart`. The customer's HTTP route
|
|
45
|
-
* handler ships full `UIMessage[]` history at the very first turn — before
|
|
46
|
-
* any snapshot exists. The route handler isn't subject to the
|
|
47
|
-
* `MAX_APPEND_BODY_BYTES` cap on `/in/append` because it goes through the
|
|
48
|
-
* customer's own HTTP endpoint. Used ONLY by `trigger: "handover-prepare"`.
|
|
49
|
-
* Ignored on every other trigger.
|
|
50
|
-
*/
|
|
51
|
-
headStartMessages?: TMessage[];
|
|
52
|
-
chatId: string;
|
|
53
|
-
trigger: "submit-message" | "regenerate-message" | "preload" | "close" | "action"
|
|
54
|
-
/**
|
|
55
|
-
* The customer's `chat.handover` route handler kicked us off in
|
|
56
|
-
* parallel with the first-turn `streamText` running in the warm
|
|
57
|
-
* Next.js process. The run sits idle on `session.in` waiting for
|
|
58
|
-
* a `kind: "handover"` (continue from tool execution) or
|
|
59
|
-
* `kind: "handover-skip"` (handler finished pure-text, exit
|
|
60
|
-
* cleanly). See `chat.handover` in `@trigger.dev/sdk/chat-server`.
|
|
61
|
-
*/
|
|
62
|
-
| "handover-prepare";
|
|
63
|
-
messageId?: string;
|
|
64
|
-
metadata?: TMetadata;
|
|
65
|
-
/** Custom action payload when `trigger` is `"action"`. Validated against `actionSchema` on the backend. */
|
|
66
|
-
action?: unknown;
|
|
67
|
-
/** Whether this run is continuing an existing chat whose previous run ended. */
|
|
68
|
-
continuation?: boolean;
|
|
69
|
-
/** The run ID of the previous run (only set when `continuation` is true). */
|
|
70
|
-
previousRunId?: string;
|
|
71
|
-
/** Override idle timeout for this run (seconds). Set by transport.preload(). */
|
|
72
|
-
idleTimeoutInSeconds?: number;
|
|
73
|
-
/**
|
|
74
|
-
* The friendlyId of the Session primitive backing this chat. The
|
|
75
|
-
* transport opens (or lazy-creates) the session with
|
|
76
|
-
* `externalId = chatId` on first message, then sends this friendlyId
|
|
77
|
-
* through to the run so the agent can attach to `.in` / `.out`
|
|
78
|
-
* without needing to round-trip through the control plane again.
|
|
79
|
-
* Optional for backward-compat while the migration is in flight;
|
|
80
|
-
* required once the legacy run-scoped stream path is removed.
|
|
81
|
-
*/
|
|
82
|
-
sessionId?: string;
|
|
83
|
-
};
|
|
84
|
-
/**
|
|
85
|
-
* One chunk on the chat input stream. `kind` discriminates the variants —
|
|
86
|
-
* a single ordered stream now carries all the signals the old three-stream
|
|
87
|
-
* split did (`chat-messages`, `chat-stop`, plus action messages piggybacked
|
|
88
|
-
* on `chat-messages`).
|
|
89
|
-
*/
|
|
90
|
-
export type ChatInputChunk<TMessage extends UIMessage = UIMessage, TMetadata = unknown> = {
|
|
91
|
-
kind: "message";
|
|
92
|
-
/**
|
|
93
|
-
* Full wire payload for a new user message or regeneration. Mirrors
|
|
94
|
-
* what the legacy `chat-messages` input stream carried.
|
|
95
|
-
*/
|
|
96
|
-
payload: ChatTaskWirePayload<TMessage, TMetadata>;
|
|
97
|
-
} | {
|
|
98
|
-
kind: "stop";
|
|
99
|
-
/** Optional human-readable reason. Maps to the legacy `chat-stop` record. */
|
|
100
|
-
message?: string;
|
|
101
|
-
} | {
|
|
102
|
-
/**
|
|
103
|
-
* Sent by `chat.headStart` when the customer's first-turn
|
|
104
|
-
* `streamText` finishes. The agent run (currently parked in
|
|
105
|
-
* `handover-prepare`) wakes, seeds its accumulators with
|
|
106
|
-
* `partialAssistantMessage`, and runs the normal turn loop
|
|
107
|
-
* (`onChatStart` → `onTurnStart` → … → `onTurnComplete`).
|
|
108
|
-
*
|
|
109
|
-
* What happens after that depends on `isFinal`:
|
|
110
|
-
*
|
|
111
|
-
* - `isFinal: false` — step 1 ended with `finishReason:
|
|
112
|
-
* "tool-calls"`. The partial carries the assistant's
|
|
113
|
-
* tool-call(s) wrapped in AI SDK's tool-approval round. The
|
|
114
|
-
* agent's `streamText` runs the approved tools and continues
|
|
115
|
-
* from step 2.
|
|
116
|
-
* - `isFinal: true` — step 1 ended pure-text (no tool calls).
|
|
117
|
-
* The partial carries the final assistant text. The agent
|
|
118
|
-
* skips the LLM call entirely (the response is already
|
|
119
|
-
* complete on the customer side) and runs `onTurnComplete`
|
|
120
|
-
* with the partial as `responseMessage` so persistence and
|
|
121
|
-
* any post-turn work fire normally.
|
|
122
|
-
*/
|
|
123
|
-
kind: "handover";
|
|
124
|
-
/** Customer's step-1 response messages (ModelMessage form). */
|
|
125
|
-
partialAssistantMessage: ModelMessage[];
|
|
126
|
-
/**
|
|
127
|
-
* The UI messageId the customer's handler used for its step-1
|
|
128
|
-
* assistant message. The agent reuses this so any post-handover
|
|
129
|
-
* chunks (tool-output-available, step-2 text, data-* parts
|
|
130
|
-
* written by hooks) merge into the SAME assistant message on
|
|
131
|
-
* the browser side instead of starting a new one.
|
|
132
|
-
*/
|
|
133
|
-
messageId?: string;
|
|
134
|
-
/**
|
|
135
|
-
* Whether the customer's step 1 is the final response. See
|
|
136
|
-
* `kind` description above for the two branches.
|
|
137
|
-
*/
|
|
138
|
-
isFinal: boolean;
|
|
139
|
-
} | {
|
|
140
|
-
/**
|
|
141
|
-
* Sent by `chat.headStart` only when the customer's handler
|
|
142
|
-
* ABORTS before producing a finishReason (e.g., dispatch error,
|
|
143
|
-
* stream cancelled before any tokens). The agent run exits
|
|
144
|
-
* cleanly without firing turn hooks. Normal pure-text and
|
|
145
|
-
* tool-call finishes go through `kind: "handover"` with the
|
|
146
|
-
* appropriate `isFinal` flag.
|
|
147
|
-
*/
|
|
148
|
-
kind: "handover-skip";
|
|
149
|
-
};
|
|
24
|
+
import type { ChatTaskWirePayload } from "./chat.js";
|
|
25
|
+
export type { ChatTaskWirePayload, ChatInputChunk } from "./chat.js";
|
|
150
26
|
/**
|
|
151
27
|
* Extracts the client-data (`metadata`) type from a chat task.
|
|
152
28
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ai-shared.js","sourceRoot":"","sources":["../../../src/v3/ai-shared.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;GAeG;;;
|
|
1
|
+
{"version":3,"file":"ai-shared.js","sourceRoot":"","sources":["../../../src/v3/ai-shared.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;GAeG;;;AAyGH,sDAiBC;AAoDD,4DAkCC;AA3MD;;;GAGG;AACU,QAAA,6BAA6B,GAAG,+BAAwC,CAAC;AA0DtF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,SAAgB,qBAAqB,CACnC,MAAc,EACd,KAGC;IAED,IAAI,KAAK,CAAC,OAAO,KAAK,gBAAgB;QAAE,OAAO,KAAK,CAAC;IACrD,IAAI,KAAK,CAAC,gBAAgB,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACtD,MAAM,MAAM,GAAG,KAAK,CAAC,gBAAgB,CAAC,KAAK,CAAC,gBAAgB,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACzE,IAAI,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IAC1B,IAAI,MAAM,CAAC,EAAE,EAAE,CAAC;QACd,MAAM,WAAW,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,MAAM,CAAC,EAAE,CAAC,CAAC;QAChE,IAAI,WAAW,KAAK,CAAC,CAAC;YAAE,OAAO,KAAK,CAAC;IACvC,CAAC;IACD,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACpB,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;GAMG;AACH,SAAS,0BAA0B,CACjC,KAAc;IAEd,OAAO,CACL,KAAK,KAAK,kBAAkB;QAC5B,KAAK,KAAK,cAAc;QACxB,KAAK,KAAK,oBAAoB;QAC9B,KAAK,KAAK,eAAe,CAC1B,CAAC;AACJ,CAAC;AAED,2EAA2E;AAC3E,SAAS,cAAc,CAAC,IAAa;IACnC,OAAO,OAAO,IAAI,KAAK,QAAQ,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,IAAI,KAAK,cAAc,CAAC,CAAC;AAC3F,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,SAAgB,wBAAwB,CAAqC,OAAa;IACxF,IAAI,CAAC,OAAO;QAAE,OAAO,OAAO,CAAC;IAC7B,IAAI,OAAO,CAAC,IAAI,KAAK,WAAW;QAAE,OAAO,OAAO,CAAC;IACjD,MAAM,KAAK,GAAG,CAAC,OAAO,CAAC,KAAK,IAAI,EAAE,CAAU,CAAC;IAC7C,MAAM,iBAAiB,GAAG,KAAK,CAAC,MAAM,CACpC,CAAC,CAAC,EAAE,EAAE,CACJ,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,0BAA0B,CAAC,CAAC,CAAC,KAAK,CAAC,CAC9F,CAAC;IACF,IAAI,iBAAiB,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,OAAO,CAAC;IACnD,MAAM,SAAS,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE;QACjD,MAAM,IAAI,GAA4B;YACpC,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,UAAU,EAAE,CAAC,CAAC,UAAU;YACxB,KAAK,EAAE,CAAC,CAAC,KAAK;SACf,CAAC;QACF,IAAI,CAAC,CAAC,IAAI,KAAK,cAAc,IAAI,OAAO,CAAC,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;YAChE,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC,QAAQ,CAAC;QAC7B,CAAC;QACD,IAAI,CAAC,CAAC,KAAK,KAAK,kBAAkB,EAAE,CAAC;YACnC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC;YACvB,IAAI,CAAC,CAAC,QAAQ,KAAK,SAAS;gBAAE,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC,QAAQ,CAAC;QAC3D,CAAC;aAAM,IAAI,CAAC,CAAC,KAAK,KAAK,cAAc,EAAE,CAAC;YACtC,IAAI,CAAC,CAAC,SAAS,KAAK,SAAS;gBAAE,IAAI,CAAC,SAAS,GAAG,CAAC,CAAC,SAAS,CAAC;YAC5D,IAAI,CAAC,CAAC,QAAQ,KAAK,SAAS;gBAAE,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC,QAAQ,CAAC;QAC3D,CAAC;aAAM,IAAI,CAAC,CAAC,KAAK,KAAK,oBAAoB,IAAI,CAAC,CAAC,KAAK,KAAK,eAAe,EAAE,CAAC;YAC3E,IAAI,CAAC,CAAC,QAAQ,KAAK,SAAS;gBAAE,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC,QAAQ,CAAC;QAC3D,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC,CAAC,CAAC;IACH,OAAO;QACL,EAAE,EAAE,OAAO,CAAC,EAAE;QACd,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,KAAK,EAAE,SAAS;KACE,CAAC;AACvB,CAAC"}
|
package/dist/commonjs/v3/ai.js
CHANGED
|
@@ -2922,6 +2922,11 @@ function chatAgent(options) {
|
|
|
2922
2922
|
// default, `inFlightUsers`). The turn-loop checks this queue ahead of
|
|
2923
2923
|
// `messagesInput.waitWithIdleTimeout` so recovered turns fire first.
|
|
2924
2924
|
const bootInjectedQueue = [];
|
|
2925
|
+
// Messages consumed by a turn's `messagesInput.on` handler, dispatched
|
|
2926
|
+
// one per turn by the end-of-turn pickup. Loop-level on purpose:
|
|
2927
|
+
// consuming a record advances the committed `.in` cursor, so entries
|
|
2928
|
+
// dropped with a turn-local buffer are lost permanently.
|
|
2929
|
+
const pendingWireMessages = [];
|
|
2925
2930
|
const couldHavePriorState = payload.continuation === true || ctx.attempt.number > 1;
|
|
2926
2931
|
// `.in` resume cursor, computed at most once per boot. The boot
|
|
2927
2932
|
// block below resolves it (snapshot field or records scan) and the
|
|
@@ -3628,6 +3633,9 @@ function chatAgent(options) {
|
|
|
3628
3633
|
} // end else (no boot-injected first turn)
|
|
3629
3634
|
}
|
|
3630
3635
|
for (let turn = 0; turn < maxTurns; turn++) {
|
|
3636
|
+
// Declared here so the finally can detach it — a handler leaked past
|
|
3637
|
+
// its turn duplicates every mid-stream message into the shared buffer.
|
|
3638
|
+
let turnMsgSub;
|
|
3631
3639
|
try {
|
|
3632
3640
|
// Extract turn-level context before entering the span. Slim
|
|
3633
3641
|
// wire: at most one delta message per record. `headStartMessages`
|
|
@@ -3703,8 +3711,6 @@ function chatAgent(options) {
|
|
|
3703
3711
|
const stopSignal = stopController.signal;
|
|
3704
3712
|
const cancelSignal = runSignal;
|
|
3705
3713
|
const combinedSignal = AbortSignal.any([runSignal, stopController.signal]);
|
|
3706
|
-
// Buffer messages that arrive during streaming
|
|
3707
|
-
const pendingMessages = [];
|
|
3708
3714
|
const pmConfig = locals_js_1.locals.get(chatPendingMessagesKey);
|
|
3709
3715
|
const msgSub = messagesInput.on(async (msg) => {
|
|
3710
3716
|
// If pendingMessages is configured, route to the steering queue
|
|
@@ -3751,8 +3757,9 @@ function chatAgent(options) {
|
|
|
3751
3757
|
return; // Don't add to wire buffer — frontend handles non-injected case
|
|
3752
3758
|
}
|
|
3753
3759
|
// No pendingMessages config — standard wire buffer for next turn
|
|
3754
|
-
|
|
3760
|
+
pendingWireMessages.push(msg);
|
|
3755
3761
|
});
|
|
3762
|
+
turnMsgSub = msgSub;
|
|
3756
3763
|
// Track new messages for this turn (user input + assistant response).
|
|
3757
3764
|
const turnNewModelMessages = [];
|
|
3758
3765
|
const turnNewUIMessages = [];
|
|
@@ -4807,9 +4814,10 @@ function chatAgent(options) {
|
|
|
4807
4814
|
return "continue";
|
|
4808
4815
|
}
|
|
4809
4816
|
// If messages arrived during streaming (without pendingMessages config),
|
|
4810
|
-
//
|
|
4811
|
-
|
|
4812
|
-
|
|
4817
|
+
// dispatch the oldest as the next turn. The rest stay queued
|
|
4818
|
+
// and drain one per turn.
|
|
4819
|
+
if (pendingWireMessages.length > 0) {
|
|
4820
|
+
currentWirePayload = pendingWireMessages.shift();
|
|
4813
4821
|
return "continue";
|
|
4814
4822
|
}
|
|
4815
4823
|
// chat.requestUpgrade() was called — exit the loop so the
|
|
@@ -4895,6 +4903,9 @@ function chatAgent(options) {
|
|
|
4895
4903
|
// Turn error handler: write an error chunk + turn-complete to the stream
|
|
4896
4904
|
// so the client sees the error, then wait for the next message instead
|
|
4897
4905
|
// of killing the entire run. This keeps the conversation alive.
|
|
4906
|
+
// Detach the turn's message handler first — left attached it would
|
|
4907
|
+
// eat the very message the wait below is waiting for.
|
|
4908
|
+
turnMsgSub?.off();
|
|
4898
4909
|
if (turnError instanceof Error &&
|
|
4899
4910
|
turnError.name === "AbortError" &&
|
|
4900
4911
|
runSignal.aborted) {
|
|
@@ -5014,6 +5025,11 @@ function chatAgent(options) {
|
|
|
5014
5025
|
currentWirePayload = bootInjectedQueue.shift();
|
|
5015
5026
|
continue;
|
|
5016
5027
|
}
|
|
5028
|
+
// Same for messages buffered during the errored turn — already consumed, idling strands them.
|
|
5029
|
+
if (pendingWireMessages.length > 0) {
|
|
5030
|
+
currentWirePayload = pendingWireMessages.shift();
|
|
5031
|
+
continue;
|
|
5032
|
+
}
|
|
5017
5033
|
// Wait for the next message — same as after a successful turn
|
|
5018
5034
|
const effectiveIdleTimeout = metadata_js_1.metadata.get(IDLE_TIMEOUT_METADATA_KEY) ??
|
|
5019
5035
|
idleTimeoutInSeconds;
|
|
@@ -5029,6 +5045,9 @@ function chatAgent(options) {
|
|
|
5029
5045
|
currentWirePayload = next.output;
|
|
5030
5046
|
// Continue to next iteration of the for loop
|
|
5031
5047
|
}
|
|
5048
|
+
finally {
|
|
5049
|
+
turnMsgSub?.off();
|
|
5050
|
+
}
|
|
5032
5051
|
}
|
|
5033
5052
|
}
|
|
5034
5053
|
finally {
|
|
@@ -5939,8 +5958,17 @@ function createChatSession(payload, options) {
|
|
|
5939
5958
|
const accumulator = new ChatMessageAccumulator();
|
|
5940
5959
|
let previousTurnUsage;
|
|
5941
5960
|
let cumulativeUsage = emptyUsage();
|
|
5961
|
+
// Messages consumed mid-turn, dispatched one per next(). Iterator-level
|
|
5962
|
+
// for the same reason as the agent loop's `pendingWireMessages`:
|
|
5963
|
+
// consumed records never replay, so a turn-local buffer loses them.
|
|
5964
|
+
const sessionPendingWire = [];
|
|
5965
|
+
// The current turn's message subscription — detached defensively at the
|
|
5966
|
+
// top of next() in case user code threw without complete()/done().
|
|
5967
|
+
let activeMsgSub;
|
|
5942
5968
|
return {
|
|
5943
5969
|
async next() {
|
|
5970
|
+
activeMsgSub?.off();
|
|
5971
|
+
activeMsgSub = undefined;
|
|
5944
5972
|
if (!booted) {
|
|
5945
5973
|
booted = true;
|
|
5946
5974
|
await seedSessionInResumeCursorForCustomLoop(currentPayload);
|
|
@@ -6000,23 +6028,29 @@ function createChatSession(payload, options) {
|
|
|
6000
6028
|
currentPayload = { ...currentPayload, continuation: true };
|
|
6001
6029
|
}
|
|
6002
6030
|
}
|
|
6003
|
-
// Subsequent turns:
|
|
6031
|
+
// Subsequent turns: drain buffered mid-turn messages first (they
|
|
6032
|
+
// were consumed and won't be re-delivered), then wait.
|
|
6004
6033
|
if (turn > 0) {
|
|
6005
|
-
|
|
6006
|
-
|
|
6007
|
-
stop.cleanup();
|
|
6008
|
-
return { done: true, value: undefined };
|
|
6034
|
+
if (sessionPendingWire.length > 0) {
|
|
6035
|
+
currentPayload = sessionPendingWire.shift();
|
|
6009
6036
|
}
|
|
6010
|
-
|
|
6011
|
-
|
|
6012
|
-
|
|
6013
|
-
|
|
6014
|
-
|
|
6015
|
-
|
|
6016
|
-
|
|
6017
|
-
|
|
6037
|
+
else {
|
|
6038
|
+
// chat.requestUpgrade() / chat.endRun() — exit before waiting
|
|
6039
|
+
if (locals_js_1.locals.get(chatUpgradeRequestedKey) || locals_js_1.locals.get(chatEndRunRequestedKey)) {
|
|
6040
|
+
stop.cleanup();
|
|
6041
|
+
return { done: true, value: undefined };
|
|
6042
|
+
}
|
|
6043
|
+
const next = await messagesInput.waitWithIdleTimeout({
|
|
6044
|
+
idleTimeoutInSeconds,
|
|
6045
|
+
timeout,
|
|
6046
|
+
spanName: "waiting for next message",
|
|
6047
|
+
});
|
|
6048
|
+
if (!next.ok || runSignal.aborted) {
|
|
6049
|
+
stop.cleanup();
|
|
6050
|
+
return { done: true, value: undefined };
|
|
6051
|
+
}
|
|
6052
|
+
currentPayload = next.output;
|
|
6018
6053
|
}
|
|
6019
|
-
currentPayload = next.output;
|
|
6020
6054
|
}
|
|
6021
6055
|
// Check limits
|
|
6022
6056
|
if (turn >= maxTurns || runSignal.aborted) {
|
|
@@ -6041,10 +6075,10 @@ function createChatSession(payload, options) {
|
|
|
6041
6075
|
clientData: currentPayload.metadata,
|
|
6042
6076
|
});
|
|
6043
6077
|
// Listen for messages during streaming (steering + next-turn buffer)
|
|
6044
|
-
const sessionPendingWire = [];
|
|
6045
6078
|
const sessionMsgSub = messagesInput.on(async (msg) => {
|
|
6046
|
-
sessionPendingWire.push(msg);
|
|
6047
6079
|
if (sessionPendingMessages) {
|
|
6080
|
+
// Steering route — the frontend re-sends non-injected
|
|
6081
|
+
// messages on turn complete, so don't also buffer the wire.
|
|
6048
6082
|
// Slim wire: at most one delta message per record. Read
|
|
6049
6083
|
// `msg.message` directly — no array slicing needed.
|
|
6050
6084
|
const lastUIMessage = msg.message;
|
|
@@ -6069,8 +6103,11 @@ function createChatSession(payload, options) {
|
|
|
6069
6103
|
/* non-fatal */
|
|
6070
6104
|
}
|
|
6071
6105
|
}
|
|
6106
|
+
return;
|
|
6072
6107
|
}
|
|
6108
|
+
sessionPendingWire.push(msg);
|
|
6073
6109
|
});
|
|
6110
|
+
activeMsgSub = sessionMsgSub;
|
|
6074
6111
|
// Accumulate messages. Slim wire: pass the single delta message as
|
|
6075
6112
|
// a 0-or-1-length array. The accumulator's behavior is unchanged —
|
|
6076
6113
|
// it still appends user messages and reconverts on regenerate.
|
|
@@ -6161,6 +6198,11 @@ function createChatSession(payload, options) {
|
|
|
6161
6198
|
throw error;
|
|
6162
6199
|
}
|
|
6163
6200
|
}
|
|
6201
|
+
finally {
|
|
6202
|
+
// Detach at stream end (like the agent loop): the steering queue
|
|
6203
|
+
// can't inject anymore, so later arrivals must buffer for the next turn.
|
|
6204
|
+
sessionMsgSub.off();
|
|
6205
|
+
}
|
|
6164
6206
|
if (response) {
|
|
6165
6207
|
const cleaned = stop.signal.aborted && !runSignal.aborted
|
|
6166
6208
|
? cleanupAbortedParts(response)
|
|
@@ -6304,6 +6346,8 @@ function createChatSession(payload, options) {
|
|
|
6304
6346
|
return { done: false, value: turnObj };
|
|
6305
6347
|
},
|
|
6306
6348
|
async return() {
|
|
6349
|
+
activeMsgSub?.off();
|
|
6350
|
+
activeMsgSub = undefined;
|
|
6307
6351
|
// `stop` only exists once next() has booted the iterator.
|
|
6308
6352
|
stop?.cleanup();
|
|
6309
6353
|
return { done: true, value: undefined };
|