Skip to content

Commit 4a1eaba

Browse files
committed
fix(sdk): TriggerChatTransport handover fail-fast + dispose aborts streams
1 parent fa4d778 commit 4a1eaba

1 file changed

Lines changed: 22 additions & 8 deletions

File tree

packages/trigger-sdk/src/v3/chat.ts

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -671,17 +671,23 @@ export class TriggerChatTransport implements ChatTransport<UIMessage> {
671671
}
672672

673673
// Hydrate session state from response headers so subsequent turns
674-
// skip the endpoint and write directly to session.in.
674+
// skip the endpoint and write directly to session.in. Failing fast
675+
// when the header is missing avoids a quiet degraded state where
676+
// every later turn re-runs the handover route instead of taking
677+
// the slim-wire path.
675678
const accessToken = response.headers.get("X-Trigger-Chat-Access-Token");
676679
const chatId = args.chatId;
677-
if (accessToken) {
678-
const state: ChatSessionState = {
679-
publicAccessToken: accessToken,
680-
isStreaming: true,
681-
};
682-
this.sessions.set(chatId, state);
683-
this.notifySessionChange(chatId, state);
680+
if (!accessToken) {
681+
throw new Error(
682+
"chat.handover response is missing the X-Trigger-Chat-Access-Token header. chat.agent's handover endpoint must echo the session PAT so the transport can hydrate."
683+
);
684684
}
685+
const state: ChatSessionState = {
686+
publicAccessToken: accessToken,
687+
isStreaming: true,
688+
};
689+
this.sessions.set(chatId, state);
690+
this.notifySessionChange(chatId, state);
685691

686692
// Filter the parsed UIMessage stream:
687693
// - Drop control chunks (`trigger:turn-complete`,
@@ -953,6 +959,14 @@ export class TriggerChatTransport implements ChatTransport<UIMessage> {
953959
this.coordinator?.removeMessagesListener(fn);
954960
}
955961
dispose(): void {
962+
// Tear down any open session.out subscriptions before the coordinator
963+
// goes away. Otherwise controllers in `activeStreams` keep reading
964+
// until they time out, leaking network and memory on every
965+
// unmount/navigation.
966+
for (const controller of this.activeStreams.values()) {
967+
controller.abort();
968+
}
969+
this.activeStreams.clear();
956970
this.coordinator?.dispose();
957971
this.coordinator = null;
958972
}

0 commit comments

Comments
 (0)