@trigger.dev/sdk 4.5.5 → 4.5.7
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 +151 -27
- 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/index.js +17 -7
- package/dist/commonjs/v3/index.js.map +1 -1
- package/dist/commonjs/v3/runs.d.ts +10 -10
- 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 +151 -27
- 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/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/docs/self-hosting/docker.mdx +19 -1
- package/docs/self-hosting/env/webapp.mdx +2 -1
- package/docs/self-hosting/kubernetes.mdx +24 -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
|
@@ -5612,31 +5612,117 @@ function createStopSignal() {
|
|
|
5612
5612
|
* The `TriggerChatTransport` intercepts this to close the ReadableStream
|
|
5613
5613
|
* for the current turn. Call after piping the response stream.
|
|
5614
5614
|
*
|
|
5615
|
+
* Returns two resume cursors for the turn boundary, both saveable from the
|
|
5616
|
+
* task instead of round-tripping them back from the client:
|
|
5617
|
+
* - `lastEventId` — the turn-complete control record's seq_num on
|
|
5618
|
+
* `session.out`; where the next turn's output stream resumes.
|
|
5619
|
+
* - `sessionInEventId` — the committed-consume cursor on `session.in` as of
|
|
5620
|
+
* this turn-complete, letting a raw loop correlate the boundary with the
|
|
5621
|
+
* exact input record it acknowledged. Trigger owns input-cursor recovery,
|
|
5622
|
+
* so this is for correlation / out-of-sync detection, not required.
|
|
5623
|
+
*
|
|
5624
|
+
* Either is `undefined` when the corresponding cursor isn't available.
|
|
5625
|
+
*
|
|
5615
5626
|
* @example
|
|
5616
5627
|
* ```ts
|
|
5617
5628
|
* await chat.pipe(result);
|
|
5618
|
-
* await chat.writeTurnComplete();
|
|
5629
|
+
* const { lastEventId, sessionInEventId } = await chat.writeTurnComplete();
|
|
5630
|
+
* await db.chats.update(chatId, { lastEventId, sessionInEventId });
|
|
5619
5631
|
* ```
|
|
5620
5632
|
*/
|
|
5621
5633
|
async function chatWriteTurnComplete(options) {
|
|
5622
|
-
await writeTurnCompleteChunk(undefined, options?.publicAccessToken);
|
|
5634
|
+
const result = await writeTurnCompleteChunk(undefined, options?.publicAccessToken);
|
|
5635
|
+
// Same cursor written to the `session-in-event-id` header inside
|
|
5636
|
+
// `writeTurnCompleteChunk`; surfaced here so the caller can persist it.
|
|
5637
|
+
const inCursor = getChatSession().in.lastDispatchedSeqNum();
|
|
5638
|
+
return {
|
|
5639
|
+
lastEventId: result?.lastEventId,
|
|
5640
|
+
...(inCursor !== undefined ? { sessionInEventId: String(inCursor) } : {}),
|
|
5641
|
+
};
|
|
5642
|
+
}
|
|
5643
|
+
/**
|
|
5644
|
+
* Pass every chunk through untouched while recording it in `buffer`. Handles
|
|
5645
|
+
* both the `AsyncIterable` and `ReadableStream` shapes `toUIMessageStream()`
|
|
5646
|
+
* can return, and propagates a source error to the consumer after buffering
|
|
5647
|
+
* whatever streamed first. See {@link pipeChatAndCapture} for why.
|
|
5648
|
+
*/
|
|
5649
|
+
async function* tapUIMessageChunks(source, buffer) {
|
|
5650
|
+
if (isReadableStream(source)) {
|
|
5651
|
+
const reader = source.getReader();
|
|
5652
|
+
try {
|
|
5653
|
+
while (true) {
|
|
5654
|
+
const { done, value } = await reader.read();
|
|
5655
|
+
if (done)
|
|
5656
|
+
break;
|
|
5657
|
+
buffer.push(value);
|
|
5658
|
+
yield value;
|
|
5659
|
+
}
|
|
5660
|
+
}
|
|
5661
|
+
finally {
|
|
5662
|
+
reader.releaseLock();
|
|
5663
|
+
}
|
|
5664
|
+
}
|
|
5665
|
+
else {
|
|
5666
|
+
for await (const chunk of source) {
|
|
5667
|
+
buffer.push(chunk);
|
|
5668
|
+
yield chunk;
|
|
5669
|
+
}
|
|
5670
|
+
}
|
|
5671
|
+
}
|
|
5672
|
+
/**
|
|
5673
|
+
* Reconstruct a partial assistant `UIMessage` from the raw chunks that
|
|
5674
|
+
* streamed before a failure — the fallback for {@link pipeChatAndCapture}
|
|
5675
|
+
* when a transport error abandons the stream before `onFinish` runs. Uses the
|
|
5676
|
+
* same `readUIMessageStream` reducer as the boot-time replay path. Returns
|
|
5677
|
+
* `undefined` if there's nothing to assemble or the reducer throws.
|
|
5678
|
+
*/
|
|
5679
|
+
async function assemblePartialFromChunks(chunks) {
|
|
5680
|
+
const relevant = chunks.filter((c) => {
|
|
5681
|
+
const type = c.type;
|
|
5682
|
+
return typeof type === "string" && !type.startsWith("trigger:");
|
|
5683
|
+
});
|
|
5684
|
+
if (relevant.length === 0)
|
|
5685
|
+
return undefined;
|
|
5686
|
+
try {
|
|
5687
|
+
const stream = new ReadableStream({
|
|
5688
|
+
start(controller) {
|
|
5689
|
+
for (const chunk of relevant)
|
|
5690
|
+
controller.enqueue(chunk);
|
|
5691
|
+
controller.close();
|
|
5692
|
+
},
|
|
5693
|
+
});
|
|
5694
|
+
let last;
|
|
5695
|
+
for await (const message of (0, ai_runtime_js_1.readUIMessageStream)({ stream })) {
|
|
5696
|
+
last = message;
|
|
5697
|
+
}
|
|
5698
|
+
return last;
|
|
5699
|
+
}
|
|
5700
|
+
catch {
|
|
5701
|
+
return undefined;
|
|
5702
|
+
}
|
|
5623
5703
|
}
|
|
5624
5704
|
/**
|
|
5625
5705
|
* Pipe a `StreamTextResult` (or similar) to the chat stream and capture
|
|
5626
5706
|
* the assistant's response message via `onFinish`.
|
|
5627
5707
|
*
|
|
5628
5708
|
* Combines `toUIMessageStream()` + `onFinish` callback + `chat.pipe()`.
|
|
5629
|
-
*
|
|
5709
|
+
* Never throws on a stopped or failed stream: it returns a
|
|
5710
|
+
* {@link PipeAndCaptureResult} whose `message` holds any partial output
|
|
5711
|
+
* captured before the stop/failure, alongside a typed `status` (and `error`
|
|
5712
|
+
* on failure). Save the partial after a stop or error without separate
|
|
5713
|
+
* capture logic.
|
|
5630
5714
|
*
|
|
5631
5715
|
* @example
|
|
5632
5716
|
* ```ts
|
|
5633
5717
|
* const result = streamText({ model, messages, abortSignal: signal });
|
|
5634
|
-
* const
|
|
5635
|
-
* if (
|
|
5718
|
+
* const { message, status, error } = await chat.pipeAndCapture(result, { signal });
|
|
5719
|
+
* if (message) conversation.addResponse(message);
|
|
5720
|
+
* if (status === "error") logger.error("turn failed", { error });
|
|
5636
5721
|
* ```
|
|
5637
5722
|
*/
|
|
5638
5723
|
async function pipeChatAndCapture(source, options) {
|
|
5639
5724
|
let captured;
|
|
5725
|
+
let capturedFinishReason;
|
|
5640
5726
|
let resolveOnFinish;
|
|
5641
5727
|
const onFinishPromise = new Promise((r) => {
|
|
5642
5728
|
resolveOnFinish = r;
|
|
@@ -5654,17 +5740,57 @@ async function pipeChatAndCapture(source, options) {
|
|
|
5654
5740
|
// the frontend replaces the partial message — wiping the
|
|
5655
5741
|
// pre-injection text from the UI and the captured response.
|
|
5656
5742
|
generateMessageId: resolvedOptions.generateMessageId ?? ai_runtime_js_1.generateId,
|
|
5657
|
-
onFinish: ({ responseMessage }) => {
|
|
5743
|
+
onFinish: ({ responseMessage, finishReason, }) => {
|
|
5658
5744
|
captured = responseMessage;
|
|
5745
|
+
capturedFinishReason = finishReason;
|
|
5659
5746
|
resolveOnFinish();
|
|
5660
5747
|
},
|
|
5661
5748
|
});
|
|
5662
|
-
|
|
5663
|
-
|
|
5664
|
-
|
|
5665
|
-
|
|
5666
|
-
|
|
5667
|
-
|
|
5749
|
+
// Buffer chunks as they flow to the pipe so a transport failure that
|
|
5750
|
+
// abandons the UI stream before `onFinish` fires — the one termination path
|
|
5751
|
+
// that skips `onFinish` — can still reconstruct the partial. This retains
|
|
5752
|
+
// chunk references only; the reassembly runs solely in the failure fallback
|
|
5753
|
+
// below, so the happy path pays nothing extra.
|
|
5754
|
+
const bufferedChunks = [];
|
|
5755
|
+
const tappedStream = tapUIMessageChunks(uiStream, bufferedChunks);
|
|
5756
|
+
let status = "complete";
|
|
5757
|
+
let error;
|
|
5758
|
+
try {
|
|
5759
|
+
await pipeChat(tappedStream, {
|
|
5760
|
+
signal: options?.signal,
|
|
5761
|
+
spanName: options?.spanName ?? "stream response",
|
|
5762
|
+
});
|
|
5763
|
+
// The pipe can drain cleanly on a stop — the source stream just ends
|
|
5764
|
+
// early — so classify by the signal rather than relying on a throw.
|
|
5765
|
+
if (options?.signal?.aborted) {
|
|
5766
|
+
status = "aborted";
|
|
5767
|
+
}
|
|
5768
|
+
}
|
|
5769
|
+
catch (err) {
|
|
5770
|
+
if ((err instanceof Error && err.name === "AbortError") || options?.signal?.aborted) {
|
|
5771
|
+
status = "aborted";
|
|
5772
|
+
}
|
|
5773
|
+
else {
|
|
5774
|
+
status = "error";
|
|
5775
|
+
error = err;
|
|
5776
|
+
}
|
|
5777
|
+
}
|
|
5778
|
+
// `onFinish` fires even on abort, carrying the partial — but a hard stop can
|
|
5779
|
+
// prevent it from firing at all, so race it against a timeout to avoid
|
|
5780
|
+
// hanging the caller. Mirrors chat.agent's capture path.
|
|
5781
|
+
await Promise.race([onFinishPromise, new Promise((r) => setTimeout(r, 2_000))]);
|
|
5782
|
+
// A transport failure can abandon the UI stream before `onFinish` fires, so
|
|
5783
|
+
// reconstruct the partial from the buffered chunks rather than losing output
|
|
5784
|
+
// that already streamed. Only runs when `onFinish` produced nothing.
|
|
5785
|
+
if (!captured && bufferedChunks.length > 0) {
|
|
5786
|
+
captured = await assemblePartialFromChunks(bufferedChunks);
|
|
5787
|
+
}
|
|
5788
|
+
return {
|
|
5789
|
+
message: captured,
|
|
5790
|
+
status,
|
|
5791
|
+
finishReason: capturedFinishReason,
|
|
5792
|
+
...(error !== undefined ? { error } : {}),
|
|
5793
|
+
};
|
|
5668
5794
|
}
|
|
5669
5795
|
/**
|
|
5670
5796
|
* Accumulates conversation messages across turns.
|
|
@@ -5679,8 +5805,8 @@ async function pipeChatAndCapture(source, options) {
|
|
|
5679
5805
|
* for (let turn = 0; turn < 100; turn++) {
|
|
5680
5806
|
* const messages = await conversation.addIncoming(payload.messages, payload.trigger, turn);
|
|
5681
5807
|
* const result = streamText({ model, messages });
|
|
5682
|
-
* const
|
|
5683
|
-
* if (
|
|
5808
|
+
* const { message } = await chat.pipeAndCapture(result);
|
|
5809
|
+
* if (message) await conversation.addResponse(message);
|
|
5684
5810
|
* }
|
|
5685
5811
|
* ```
|
|
5686
5812
|
*/
|
|
@@ -6174,7 +6300,7 @@ function createChatSession(payload, options) {
|
|
|
6174
6300
|
}
|
|
6175
6301
|
let response;
|
|
6176
6302
|
try {
|
|
6177
|
-
|
|
6303
|
+
const captured = await pipeChatAndCapture(source, {
|
|
6178
6304
|
signal: combinedSignal,
|
|
6179
6305
|
// On a non-final handover turn, thread the spliced partial so a
|
|
6180
6306
|
// resumed tool round's tool-output chunks merge into the
|
|
@@ -6183,20 +6309,18 @@ function createChatSession(payload, options) {
|
|
|
6183
6309
|
// fresh response into the prior assistant message).
|
|
6184
6310
|
...(handoverThisTurn ? { originalMessages: accumulator.uiMessages } : {}),
|
|
6185
6311
|
});
|
|
6186
|
-
|
|
6187
|
-
|
|
6188
|
-
|
|
6189
|
-
|
|
6190
|
-
|
|
6191
|
-
sessionMsgSub.off();
|
|
6192
|
-
await chatWriteTurnComplete();
|
|
6193
|
-
return undefined;
|
|
6194
|
-
}
|
|
6195
|
-
// Stop — fall through to accumulate partial response
|
|
6312
|
+
if (runSignal.aborted) {
|
|
6313
|
+
// Full cancel — don't accumulate
|
|
6314
|
+
sessionMsgSub.off();
|
|
6315
|
+
await chatWriteTurnComplete();
|
|
6316
|
+
return undefined;
|
|
6196
6317
|
}
|
|
6197
|
-
|
|
6198
|
-
|
|
6318
|
+
// Surface a genuine stream failure to the caller. A user stop
|
|
6319
|
+
// (status "aborted") falls through so the partial is accumulated.
|
|
6320
|
+
if (captured.status === "error") {
|
|
6321
|
+
throw captured.error;
|
|
6199
6322
|
}
|
|
6323
|
+
response = captured.message;
|
|
6200
6324
|
}
|
|
6201
6325
|
finally {
|
|
6202
6326
|
// Detach at stream end (like the agent loop): the steering queue
|