@trigger.dev/sdk 0.0.0-prerelease-20260304181730 → 0.0.0-prerelease-20260305142821
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 +118 -16
- package/dist/commonjs/v3/ai.js +212 -33
- package/dist/commonjs/v3/ai.js.map +1 -1
- package/dist/commonjs/v3/chat-react.d.ts +3 -0
- package/dist/commonjs/v3/chat-react.js +8 -0
- package/dist/commonjs/v3/chat-react.js.map +1 -1
- package/dist/commonjs/v3/chat.d.ts +85 -0
- package/dist/commonjs/v3/chat.js +76 -3
- package/dist/commonjs/v3/chat.js.map +1 -1
- package/dist/commonjs/v3/chat.test.js +325 -72
- package/dist/commonjs/v3/chat.test.js.map +1 -1
- package/dist/commonjs/version.js +1 -1
- package/dist/esm/v3/ai.d.ts +118 -16
- package/dist/esm/v3/ai.js +212 -33
- package/dist/esm/v3/ai.js.map +1 -1
- package/dist/esm/v3/chat-react.d.ts +3 -0
- package/dist/esm/v3/chat-react.js +9 -1
- package/dist/esm/v3/chat-react.js.map +1 -1
- package/dist/esm/v3/chat.d.ts +85 -0
- package/dist/esm/v3/chat.js +76 -3
- package/dist/esm/v3/chat.js.map +1 -1
- package/dist/esm/v3/chat.test.js +325 -72
- package/dist/esm/v3/chat.test.js.map +1 -1
- package/dist/esm/version.js +1 -1
- package/package.json +2 -2
package/dist/esm/v3/chat.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat.js","sourceRoot":"","sources":["../../../src/v3/chat.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAGH,OAAO,EAAE,SAAS,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AACxE,OAAO,EAAE,uBAAuB,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAEnF,MAAM,kBAAkB,GAAG,MAAM,CAAC;AAClC,MAAM,gBAAgB,GAAG,yBAAyB,CAAC;AACnD,MAAM,8BAA8B,GAAG,GAAG,CAAC;
|
|
1
|
+
{"version":3,"file":"chat.js","sourceRoot":"","sources":["../../../src/v3/chat.ts"],"names":[],"mappings":"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"}
|
package/dist/esm/v3/chat.test.js
CHANGED
|
@@ -514,6 +514,7 @@ describe("TriggerChatTransport", () => {
|
|
|
514
514
|
describe("multiple sessions", () => {
|
|
515
515
|
it("should track multiple chat sessions independently", async () => {
|
|
516
516
|
let callCount = 0;
|
|
517
|
+
const turnCompleteChunk = { type: "__trigger_turn_complete" };
|
|
517
518
|
global.fetch = vi.fn().mockImplementation(async (url) => {
|
|
518
519
|
const urlStr = typeof url === "string" ? url : url.toString();
|
|
519
520
|
if (urlStr.includes("/trigger")) {
|
|
@@ -527,7 +528,9 @@ describe("TriggerChatTransport", () => {
|
|
|
527
528
|
});
|
|
528
529
|
}
|
|
529
530
|
if (urlStr.includes("/realtime/v1/streams/")) {
|
|
530
|
-
|
|
531
|
+
// Include turn-complete chunk so the session is preserved
|
|
532
|
+
const chunks = [...sampleChunks, turnCompleteChunk];
|
|
533
|
+
return new Response(createSSEStream(sseEncode(chunks)), {
|
|
531
534
|
status: 200,
|
|
532
535
|
headers: {
|
|
533
536
|
"content-type": "text/event-stream",
|
|
@@ -542,21 +545,25 @@ describe("TriggerChatTransport", () => {
|
|
|
542
545
|
accessToken: "token",
|
|
543
546
|
baseURL: "https://api.test.trigger.dev",
|
|
544
547
|
});
|
|
545
|
-
// Start two independent chat sessions
|
|
546
|
-
await transport.sendMessages({
|
|
548
|
+
// Start two independent chat sessions and consume the streams
|
|
549
|
+
const s1 = await transport.sendMessages({
|
|
547
550
|
trigger: "submit-message",
|
|
548
551
|
chatId: "session-a",
|
|
549
552
|
messageId: undefined,
|
|
550
553
|
messages: [createUserMessage("Hello A")],
|
|
551
554
|
abortSignal: undefined,
|
|
552
555
|
});
|
|
553
|
-
|
|
556
|
+
const r1 = s1.getReader();
|
|
557
|
+
while (!(await r1.read()).done) { }
|
|
558
|
+
const s2 = await transport.sendMessages({
|
|
554
559
|
trigger: "submit-message",
|
|
555
560
|
chatId: "session-b",
|
|
556
561
|
messageId: undefined,
|
|
557
562
|
messages: [createUserMessage("Hello B")],
|
|
558
563
|
abortSignal: undefined,
|
|
559
564
|
});
|
|
565
|
+
const r2 = s2.getReader();
|
|
566
|
+
while (!(await r2.read()).done) { }
|
|
560
567
|
// Both sessions should be independently reconnectable
|
|
561
568
|
const streamA = await transport.reconnectToStream({ chatId: "session-a" });
|
|
562
569
|
const streamB = await transport.reconnectToStream({ chatId: "session-b" });
|
|
@@ -725,11 +732,7 @@ describe("TriggerChatTransport", () => {
|
|
|
725
732
|
});
|
|
726
733
|
describe("lastEventId tracking", () => {
|
|
727
734
|
it("should pass lastEventId to SSE subscription on subsequent turns", async () => {
|
|
728
|
-
const
|
|
729
|
-
type: "__trigger_waitpoint_ready",
|
|
730
|
-
tokenId: "wp_token_eid",
|
|
731
|
-
publicAccessToken: "wp_access_eid",
|
|
732
|
-
};
|
|
735
|
+
const turnCompleteChunk = { type: "__trigger_turn_complete" };
|
|
733
736
|
let triggerCallCount = 0;
|
|
734
737
|
const streamFetchCalls = [];
|
|
735
738
|
global.fetch = vi.fn().mockImplementation(async (url, init) => {
|
|
@@ -744,8 +747,9 @@ describe("TriggerChatTransport", () => {
|
|
|
744
747
|
},
|
|
745
748
|
});
|
|
746
749
|
}
|
|
747
|
-
|
|
748
|
-
|
|
750
|
+
// Handle input stream sends (for second message)
|
|
751
|
+
if (urlStr.includes("/realtime/v1/streams/") && urlStr.includes("/input/")) {
|
|
752
|
+
return new Response(JSON.stringify({ ok: true }), {
|
|
749
753
|
status: 200,
|
|
750
754
|
headers: { "content-type": "application/json" },
|
|
751
755
|
});
|
|
@@ -758,7 +762,7 @@ describe("TriggerChatTransport", () => {
|
|
|
758
762
|
const chunks = [
|
|
759
763
|
...sampleChunks,
|
|
760
764
|
{ type: "finish", id: "part-1" },
|
|
761
|
-
|
|
765
|
+
turnCompleteChunk,
|
|
762
766
|
];
|
|
763
767
|
return new Response(createSSEStream(sseEncode(chunks)), {
|
|
764
768
|
status: 200,
|
|
@@ -789,7 +793,7 @@ describe("TriggerChatTransport", () => {
|
|
|
789
793
|
if (done)
|
|
790
794
|
break;
|
|
791
795
|
}
|
|
792
|
-
// Second message —
|
|
796
|
+
// Second message — sends via input stream
|
|
793
797
|
const stream2 = await transport.sendMessages({
|
|
794
798
|
trigger: "submit-message",
|
|
795
799
|
chatId: "chat-eid",
|
|
@@ -810,13 +814,125 @@ describe("TriggerChatTransport", () => {
|
|
|
810
814
|
expect(secondStreamHeaders["Last-Event-ID"]).toBeDefined();
|
|
811
815
|
});
|
|
812
816
|
});
|
|
817
|
+
describe("minimal wire payloads", () => {
|
|
818
|
+
it("should send only new messages via input stream on turn 2+", async () => {
|
|
819
|
+
const turnCompleteChunk = { type: "__trigger_turn_complete" };
|
|
820
|
+
const inputStreamPayloads = [];
|
|
821
|
+
global.fetch = vi.fn().mockImplementation(async (url, init) => {
|
|
822
|
+
const urlStr = typeof url === "string" ? url : url.toString();
|
|
823
|
+
if (urlStr.includes("/api/v1/tasks/") && urlStr.includes("/trigger")) {
|
|
824
|
+
return new Response(JSON.stringify({ id: "run_minimal" }), {
|
|
825
|
+
status: 200,
|
|
826
|
+
headers: {
|
|
827
|
+
"content-type": "application/json",
|
|
828
|
+
"x-trigger-jwt": "pub_token_minimal",
|
|
829
|
+
},
|
|
830
|
+
});
|
|
831
|
+
}
|
|
832
|
+
// Capture input stream payloads (ApiClient wraps in { data: ... })
|
|
833
|
+
if (urlStr.includes("/realtime/v1/streams/") && urlStr.includes("/input/")) {
|
|
834
|
+
const body = JSON.parse(init?.body);
|
|
835
|
+
inputStreamPayloads.push(body.data);
|
|
836
|
+
return new Response(JSON.stringify({ ok: true }), {
|
|
837
|
+
status: 200,
|
|
838
|
+
headers: { "content-type": "application/json" },
|
|
839
|
+
});
|
|
840
|
+
}
|
|
841
|
+
if (urlStr.includes("/realtime/v1/streams/")) {
|
|
842
|
+
const chunks = [
|
|
843
|
+
...sampleChunks,
|
|
844
|
+
turnCompleteChunk,
|
|
845
|
+
];
|
|
846
|
+
return new Response(createSSEStream(sseEncode(chunks)), {
|
|
847
|
+
status: 200,
|
|
848
|
+
headers: {
|
|
849
|
+
"content-type": "text/event-stream",
|
|
850
|
+
"X-Stream-Version": "v1",
|
|
851
|
+
},
|
|
852
|
+
});
|
|
853
|
+
}
|
|
854
|
+
throw new Error(`Unexpected fetch URL: ${urlStr}`);
|
|
855
|
+
});
|
|
856
|
+
const transport = new TriggerChatTransport({
|
|
857
|
+
task: "my-task",
|
|
858
|
+
accessToken: "token",
|
|
859
|
+
baseURL: "https://api.test.trigger.dev",
|
|
860
|
+
});
|
|
861
|
+
const userMsg1 = createUserMessage("Hello");
|
|
862
|
+
const assistantMsg = createAssistantMessage("Hi there!");
|
|
863
|
+
const userMsg2 = createUserMessage("What's up?");
|
|
864
|
+
// Turn 1 — triggers a new run with full history
|
|
865
|
+
const stream1 = await transport.sendMessages({
|
|
866
|
+
trigger: "submit-message",
|
|
867
|
+
chatId: "chat-minimal",
|
|
868
|
+
messageId: undefined,
|
|
869
|
+
messages: [userMsg1],
|
|
870
|
+
abortSignal: undefined,
|
|
871
|
+
});
|
|
872
|
+
const r1 = stream1.getReader();
|
|
873
|
+
while (!(await r1.read()).done) { }
|
|
874
|
+
// Turn 2 — sends via input stream, should only include NEW messages
|
|
875
|
+
const stream2 = await transport.sendMessages({
|
|
876
|
+
trigger: "submit-message",
|
|
877
|
+
chatId: "chat-minimal",
|
|
878
|
+
messageId: undefined,
|
|
879
|
+
messages: [userMsg1, assistantMsg, userMsg2],
|
|
880
|
+
abortSignal: undefined,
|
|
881
|
+
});
|
|
882
|
+
const r2 = stream2.getReader();
|
|
883
|
+
while (!(await r2.read()).done) { }
|
|
884
|
+
// Verify: the input stream payload should only contain the new user message
|
|
885
|
+
expect(inputStreamPayloads).toHaveLength(1);
|
|
886
|
+
const sentPayload = inputStreamPayloads[0];
|
|
887
|
+
// Only the new user message should be sent (backend already has the assistant response)
|
|
888
|
+
expect(sentPayload.messages).toHaveLength(1);
|
|
889
|
+
expect(sentPayload.messages[0]).toEqual(userMsg2);
|
|
890
|
+
});
|
|
891
|
+
it("should send full history on first message (trigger)", async () => {
|
|
892
|
+
let triggerPayload;
|
|
893
|
+
global.fetch = vi.fn().mockImplementation(async (url, init) => {
|
|
894
|
+
const urlStr = typeof url === "string" ? url : url.toString();
|
|
895
|
+
if (urlStr.includes("/api/v1/tasks/") && urlStr.includes("/trigger")) {
|
|
896
|
+
triggerPayload = JSON.parse(init?.body);
|
|
897
|
+
return new Response(JSON.stringify({ id: "run_full" }), {
|
|
898
|
+
status: 200,
|
|
899
|
+
headers: {
|
|
900
|
+
"content-type": "application/json",
|
|
901
|
+
"x-trigger-jwt": "pub_token_full",
|
|
902
|
+
},
|
|
903
|
+
});
|
|
904
|
+
}
|
|
905
|
+
if (urlStr.includes("/realtime/v1/streams/")) {
|
|
906
|
+
return new Response(createSSEStream(sseEncode(sampleChunks)), {
|
|
907
|
+
status: 200,
|
|
908
|
+
headers: {
|
|
909
|
+
"content-type": "text/event-stream",
|
|
910
|
+
"X-Stream-Version": "v1",
|
|
911
|
+
},
|
|
912
|
+
});
|
|
913
|
+
}
|
|
914
|
+
throw new Error(`Unexpected fetch URL: ${urlStr}`);
|
|
915
|
+
});
|
|
916
|
+
const transport = new TriggerChatTransport({
|
|
917
|
+
task: "my-task",
|
|
918
|
+
accessToken: "token",
|
|
919
|
+
baseURL: "https://api.test.trigger.dev",
|
|
920
|
+
});
|
|
921
|
+
const messages = [createUserMessage("Hello"), createAssistantMessage("Hi!"), createUserMessage("More")];
|
|
922
|
+
await transport.sendMessages({
|
|
923
|
+
trigger: "submit-message",
|
|
924
|
+
chatId: "chat-full",
|
|
925
|
+
messageId: undefined,
|
|
926
|
+
messages,
|
|
927
|
+
abortSignal: undefined,
|
|
928
|
+
});
|
|
929
|
+
// First message always sends full history via trigger
|
|
930
|
+
expect(triggerPayload.payload.messages).toHaveLength(3);
|
|
931
|
+
});
|
|
932
|
+
});
|
|
813
933
|
describe("AbortController cleanup", () => {
|
|
814
934
|
it("should terminate SSE connection after intercepting control chunk", async () => {
|
|
815
|
-
const controlChunk = {
|
|
816
|
-
type: "__trigger_waitpoint_ready",
|
|
817
|
-
tokenId: "wp_token_abort",
|
|
818
|
-
publicAccessToken: "wp_access_abort",
|
|
819
|
-
};
|
|
935
|
+
const controlChunk = { type: "__trigger_turn_complete" };
|
|
820
936
|
let streamAborted = false;
|
|
821
937
|
global.fetch = vi.fn().mockImplementation(async (url, init) => {
|
|
822
938
|
const urlStr = typeof url === "string" ? url : url.toString();
|
|
@@ -923,14 +1039,10 @@ describe("TriggerChatTransport", () => {
|
|
|
923
1039
|
});
|
|
924
1040
|
expect(tokenCallCount).toBe(1);
|
|
925
1041
|
});
|
|
926
|
-
it("should resolve async token for
|
|
927
|
-
const
|
|
928
|
-
type: "__trigger_waitpoint_ready",
|
|
929
|
-
tokenId: "wp_token_async",
|
|
930
|
-
publicAccessToken: "wp_access_async",
|
|
931
|
-
};
|
|
1042
|
+
it("should not resolve async token for input stream send flow", async () => {
|
|
1043
|
+
const turnCompleteChunk = { type: "__trigger_turn_complete" };
|
|
932
1044
|
let tokenCallCount = 0;
|
|
933
|
-
let
|
|
1045
|
+
let inputStreamSendCalled = false;
|
|
934
1046
|
global.fetch = vi.fn().mockImplementation(async (url) => {
|
|
935
1047
|
const urlStr = typeof url === "string" ? url : url.toString();
|
|
936
1048
|
if (urlStr.includes("/api/v1/tasks/") && urlStr.includes("/trigger")) {
|
|
@@ -942,9 +1054,10 @@ describe("TriggerChatTransport", () => {
|
|
|
942
1054
|
},
|
|
943
1055
|
});
|
|
944
1056
|
}
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
1057
|
+
// Handle input stream sends
|
|
1058
|
+
if (urlStr.includes("/realtime/v1/streams/") && urlStr.includes("/input/")) {
|
|
1059
|
+
inputStreamSendCalled = true;
|
|
1060
|
+
return new Response(JSON.stringify({ ok: true }), {
|
|
948
1061
|
status: 200,
|
|
949
1062
|
headers: { "content-type": "application/json" },
|
|
950
1063
|
});
|
|
@@ -953,7 +1066,7 @@ describe("TriggerChatTransport", () => {
|
|
|
953
1066
|
const chunks = [
|
|
954
1067
|
...sampleChunks,
|
|
955
1068
|
{ type: "finish", id: "part-1" },
|
|
956
|
-
|
|
1069
|
+
turnCompleteChunk,
|
|
957
1070
|
];
|
|
958
1071
|
return new Response(createSSEStream(sseEncode(chunks)), {
|
|
959
1072
|
status: 200,
|
|
@@ -989,7 +1102,7 @@ describe("TriggerChatTransport", () => {
|
|
|
989
1102
|
break;
|
|
990
1103
|
}
|
|
991
1104
|
const firstTokenCount = tokenCallCount;
|
|
992
|
-
// Second message — should
|
|
1105
|
+
// Second message — should send via input stream (does NOT call async token)
|
|
993
1106
|
const stream2 = await transport.sendMessages({
|
|
994
1107
|
trigger: "submit-message",
|
|
995
1108
|
chatId: "chat-async-wp",
|
|
@@ -1003,18 +1116,14 @@ describe("TriggerChatTransport", () => {
|
|
|
1003
1116
|
if (done)
|
|
1004
1117
|
break;
|
|
1005
1118
|
}
|
|
1006
|
-
// Token function should NOT have been called again for the
|
|
1119
|
+
// Token function should NOT have been called again for the input stream path
|
|
1007
1120
|
expect(tokenCallCount).toBe(firstTokenCount);
|
|
1008
|
-
expect(
|
|
1121
|
+
expect(inputStreamSendCalled).toBe(true);
|
|
1009
1122
|
});
|
|
1010
1123
|
});
|
|
1011
|
-
describe("single-run mode (
|
|
1012
|
-
it("should
|
|
1013
|
-
const
|
|
1014
|
-
type: "__trigger_waitpoint_ready",
|
|
1015
|
-
tokenId: "wp_token_123",
|
|
1016
|
-
publicAccessToken: "wp_access_abc",
|
|
1017
|
-
};
|
|
1124
|
+
describe("single-run mode (input stream loop)", () => {
|
|
1125
|
+
it("should not forward turn-complete control chunk to consumer", async () => {
|
|
1126
|
+
const turnCompleteChunk = { type: "__trigger_turn_complete" };
|
|
1018
1127
|
global.fetch = vi.fn().mockImplementation(async (url) => {
|
|
1019
1128
|
const urlStr = typeof url === "string" ? url : url.toString();
|
|
1020
1129
|
if (urlStr.includes("/trigger")) {
|
|
@@ -1030,7 +1139,7 @@ describe("TriggerChatTransport", () => {
|
|
|
1030
1139
|
const chunks = [
|
|
1031
1140
|
...sampleChunks,
|
|
1032
1141
|
{ type: "finish", id: "part-1" },
|
|
1033
|
-
|
|
1142
|
+
turnCompleteChunk,
|
|
1034
1143
|
];
|
|
1035
1144
|
return new Response(createSSEStream(sseEncode(chunks)), {
|
|
1036
1145
|
status: 200,
|
|
@@ -1066,16 +1175,12 @@ describe("TriggerChatTransport", () => {
|
|
|
1066
1175
|
// All AI SDK chunks should be forwarded
|
|
1067
1176
|
expect(receivedChunks.length).toBe(sampleChunks.length + 1); // +1 for the finish chunk
|
|
1068
1177
|
// Control chunk should not be in the output
|
|
1069
|
-
expect(receivedChunks.every((c) => c.type !== "
|
|
1178
|
+
expect(receivedChunks.every((c) => c.type !== "__trigger_turn_complete")).toBe(true);
|
|
1070
1179
|
});
|
|
1071
|
-
it("should
|
|
1072
|
-
const
|
|
1073
|
-
type: "__trigger_waitpoint_ready",
|
|
1074
|
-
tokenId: "wp_token_456",
|
|
1075
|
-
publicAccessToken: "wp_access_def",
|
|
1076
|
-
};
|
|
1180
|
+
it("should send via input stream on second message instead of triggering a new run", async () => {
|
|
1181
|
+
const turnCompleteChunk = { type: "__trigger_turn_complete" };
|
|
1077
1182
|
let triggerCallCount = 0;
|
|
1078
|
-
let
|
|
1183
|
+
let inputStreamSendCalled = false;
|
|
1079
1184
|
global.fetch = vi.fn().mockImplementation(async (url, init) => {
|
|
1080
1185
|
const urlStr = typeof url === "string" ? url : url.toString();
|
|
1081
1186
|
if (urlStr.includes("/api/v1/tasks/") && urlStr.includes("/trigger")) {
|
|
@@ -1088,10 +1193,10 @@ describe("TriggerChatTransport", () => {
|
|
|
1088
1193
|
},
|
|
1089
1194
|
});
|
|
1090
1195
|
}
|
|
1091
|
-
// Handle
|
|
1092
|
-
if (urlStr.includes("/
|
|
1093
|
-
|
|
1094
|
-
return new Response(JSON.stringify({
|
|
1196
|
+
// Handle input stream sends
|
|
1197
|
+
if (urlStr.includes("/realtime/v1/streams/") && urlStr.includes("/input/")) {
|
|
1198
|
+
inputStreamSendCalled = true;
|
|
1199
|
+
return new Response(JSON.stringify({ ok: true }), {
|
|
1095
1200
|
status: 200,
|
|
1096
1201
|
headers: { "content-type": "application/json" },
|
|
1097
1202
|
});
|
|
@@ -1100,7 +1205,7 @@ describe("TriggerChatTransport", () => {
|
|
|
1100
1205
|
const chunks = [
|
|
1101
1206
|
...sampleChunks,
|
|
1102
1207
|
{ type: "finish", id: "part-1" },
|
|
1103
|
-
|
|
1208
|
+
turnCompleteChunk,
|
|
1104
1209
|
];
|
|
1105
1210
|
return new Response(createSSEStream(sseEncode(chunks)), {
|
|
1106
1211
|
status: 200,
|
|
@@ -1125,7 +1230,7 @@ describe("TriggerChatTransport", () => {
|
|
|
1125
1230
|
messages: [createUserMessage("Hello")],
|
|
1126
1231
|
abortSignal: undefined,
|
|
1127
1232
|
});
|
|
1128
|
-
// Consume stream
|
|
1233
|
+
// Consume stream
|
|
1129
1234
|
const reader1 = stream1.getReader();
|
|
1130
1235
|
while (true) {
|
|
1131
1236
|
const { done } = await reader1.read();
|
|
@@ -1133,7 +1238,7 @@ describe("TriggerChatTransport", () => {
|
|
|
1133
1238
|
break;
|
|
1134
1239
|
}
|
|
1135
1240
|
expect(triggerCallCount).toBe(1);
|
|
1136
|
-
// Second message — should
|
|
1241
|
+
// Second message — should send via input stream instead of triggering
|
|
1137
1242
|
const stream2 = await transport.sendMessages({
|
|
1138
1243
|
trigger: "submit-message",
|
|
1139
1244
|
chatId: "chat-resume",
|
|
@@ -1150,8 +1255,8 @@ describe("TriggerChatTransport", () => {
|
|
|
1150
1255
|
}
|
|
1151
1256
|
// Should NOT have triggered a second run
|
|
1152
1257
|
expect(triggerCallCount).toBe(1);
|
|
1153
|
-
// Should have
|
|
1154
|
-
expect(
|
|
1258
|
+
// Should have sent via input stream
|
|
1259
|
+
expect(inputStreamSendCalled).toBe(true);
|
|
1155
1260
|
});
|
|
1156
1261
|
it("should fall back to triggering a new run if stream closes without control chunk", async () => {
|
|
1157
1262
|
let triggerCallCount = 0;
|
|
@@ -1215,12 +1320,8 @@ describe("TriggerChatTransport", () => {
|
|
|
1215
1320
|
// Should have triggered a second run
|
|
1216
1321
|
expect(triggerCallCount).toBe(2);
|
|
1217
1322
|
});
|
|
1218
|
-
it("should fall back to new run when
|
|
1219
|
-
const
|
|
1220
|
-
type: "__trigger_waitpoint_ready",
|
|
1221
|
-
tokenId: "wp_token_fail",
|
|
1222
|
-
publicAccessToken: "wp_access_fail",
|
|
1223
|
-
};
|
|
1323
|
+
it("should fall back to new run when sendInputStream fails", async () => {
|
|
1324
|
+
const turnCompleteChunk = { type: "__trigger_turn_complete" };
|
|
1224
1325
|
let triggerCallCount = 0;
|
|
1225
1326
|
global.fetch = vi.fn().mockImplementation(async (url) => {
|
|
1226
1327
|
const urlStr = typeof url === "string" ? url : url.toString();
|
|
@@ -1234,22 +1335,19 @@ describe("TriggerChatTransport", () => {
|
|
|
1234
1335
|
},
|
|
1235
1336
|
});
|
|
1236
1337
|
}
|
|
1237
|
-
//
|
|
1238
|
-
if (urlStr.includes("/
|
|
1239
|
-
return new Response(JSON.stringify({ error: "
|
|
1240
|
-
status:
|
|
1338
|
+
// Input stream send fails
|
|
1339
|
+
if (urlStr.includes("/realtime/v1/streams/") && urlStr.includes("/input/")) {
|
|
1340
|
+
return new Response(JSON.stringify({ error: "Run not found" }), {
|
|
1341
|
+
status: 404,
|
|
1241
1342
|
headers: { "content-type": "application/json" },
|
|
1242
1343
|
});
|
|
1243
1344
|
}
|
|
1244
1345
|
if (urlStr.includes("/realtime/v1/streams/")) {
|
|
1245
|
-
// First call has control chunk, subsequent calls don't
|
|
1246
1346
|
const chunks = [
|
|
1247
1347
|
...sampleChunks,
|
|
1248
1348
|
{ type: "finish", id: "part-1" },
|
|
1349
|
+
turnCompleteChunk,
|
|
1249
1350
|
];
|
|
1250
|
-
if (triggerCallCount <= 1) {
|
|
1251
|
-
chunks.push(controlChunk);
|
|
1252
|
-
}
|
|
1253
1351
|
return new Response(createSSEStream(sseEncode(chunks)), {
|
|
1254
1352
|
status: 200,
|
|
1255
1353
|
headers: {
|
|
@@ -1280,7 +1378,7 @@ describe("TriggerChatTransport", () => {
|
|
|
1280
1378
|
break;
|
|
1281
1379
|
}
|
|
1282
1380
|
expect(triggerCallCount).toBe(1);
|
|
1283
|
-
// Second message —
|
|
1381
|
+
// Second message — sendInputStream will fail, should fall back to new run
|
|
1284
1382
|
const stream2 = await transport.sendMessages({
|
|
1285
1383
|
trigger: "submit-message",
|
|
1286
1384
|
chatId: "chat-fail",
|
|
@@ -1298,5 +1396,160 @@ describe("TriggerChatTransport", () => {
|
|
|
1298
1396
|
expect(triggerCallCount).toBe(2);
|
|
1299
1397
|
});
|
|
1300
1398
|
});
|
|
1399
|
+
describe("onSessionChange", () => {
|
|
1400
|
+
it("should fire when a new session is created", async () => {
|
|
1401
|
+
const onSessionChange = vi.fn();
|
|
1402
|
+
const triggerRunId = "run_session_new";
|
|
1403
|
+
const publicToken = "pub_session_new";
|
|
1404
|
+
global.fetch = vi.fn().mockImplementation(async (url) => {
|
|
1405
|
+
const urlStr = typeof url === "string" ? url : url.toString();
|
|
1406
|
+
if (urlStr.includes("/trigger")) {
|
|
1407
|
+
return new Response(JSON.stringify({ id: triggerRunId }), {
|
|
1408
|
+
status: 200,
|
|
1409
|
+
headers: {
|
|
1410
|
+
"content-type": "application/json",
|
|
1411
|
+
"x-trigger-jwt": publicToken,
|
|
1412
|
+
},
|
|
1413
|
+
});
|
|
1414
|
+
}
|
|
1415
|
+
if (urlStr.includes("/realtime/v1/streams/")) {
|
|
1416
|
+
const chunks = [
|
|
1417
|
+
...sampleChunks,
|
|
1418
|
+
{ type: "__trigger_turn_complete" },
|
|
1419
|
+
];
|
|
1420
|
+
return new Response(createSSEStream(sseEncode(chunks)), {
|
|
1421
|
+
status: 200,
|
|
1422
|
+
headers: {
|
|
1423
|
+
"content-type": "text/event-stream",
|
|
1424
|
+
"X-Stream-Version": "v1",
|
|
1425
|
+
},
|
|
1426
|
+
});
|
|
1427
|
+
}
|
|
1428
|
+
throw new Error(`Unexpected fetch URL: ${urlStr}`);
|
|
1429
|
+
});
|
|
1430
|
+
const transport = new TriggerChatTransport({
|
|
1431
|
+
task: "my-task",
|
|
1432
|
+
accessToken: "token",
|
|
1433
|
+
baseURL: "https://api.test.trigger.dev",
|
|
1434
|
+
onSessionChange,
|
|
1435
|
+
});
|
|
1436
|
+
const stream = await transport.sendMessages({
|
|
1437
|
+
trigger: "submit-message",
|
|
1438
|
+
chatId: "chat-1",
|
|
1439
|
+
messageId: undefined,
|
|
1440
|
+
messages: [createUserMessage("Hello")],
|
|
1441
|
+
abortSignal: undefined,
|
|
1442
|
+
});
|
|
1443
|
+
// Session created notification should have fired
|
|
1444
|
+
expect(onSessionChange).toHaveBeenCalledWith("chat-1", {
|
|
1445
|
+
runId: triggerRunId,
|
|
1446
|
+
publicAccessToken: publicToken,
|
|
1447
|
+
lastEventId: undefined,
|
|
1448
|
+
});
|
|
1449
|
+
// Consume stream
|
|
1450
|
+
const reader = stream.getReader();
|
|
1451
|
+
while (!(await reader.read()).done) { }
|
|
1452
|
+
// Should also fire with updated lastEventId on turn complete
|
|
1453
|
+
const lastCall = onSessionChange.mock.calls[onSessionChange.mock.calls.length - 1];
|
|
1454
|
+
expect(lastCall[0]).toBe("chat-1");
|
|
1455
|
+
expect(lastCall[1]).not.toBeNull();
|
|
1456
|
+
expect(lastCall[1].lastEventId).toBeDefined();
|
|
1457
|
+
});
|
|
1458
|
+
it("should fire with null when session is deleted (stream ends naturally)", async () => {
|
|
1459
|
+
const onSessionChange = vi.fn();
|
|
1460
|
+
global.fetch = vi.fn().mockImplementation(async (url) => {
|
|
1461
|
+
const urlStr = typeof url === "string" ? url : url.toString();
|
|
1462
|
+
if (urlStr.includes("/trigger")) {
|
|
1463
|
+
return new Response(JSON.stringify({ id: "run_end" }), {
|
|
1464
|
+
status: 200,
|
|
1465
|
+
headers: {
|
|
1466
|
+
"content-type": "application/json",
|
|
1467
|
+
"x-trigger-jwt": "pub_end",
|
|
1468
|
+
},
|
|
1469
|
+
});
|
|
1470
|
+
}
|
|
1471
|
+
if (urlStr.includes("/realtime/v1/streams/")) {
|
|
1472
|
+
// No turn-complete chunk — stream ends naturally (run completed)
|
|
1473
|
+
return new Response(createSSEStream(sseEncode(sampleChunks)), {
|
|
1474
|
+
status: 200,
|
|
1475
|
+
headers: {
|
|
1476
|
+
"content-type": "text/event-stream",
|
|
1477
|
+
"X-Stream-Version": "v1",
|
|
1478
|
+
},
|
|
1479
|
+
});
|
|
1480
|
+
}
|
|
1481
|
+
throw new Error(`Unexpected fetch URL: ${urlStr}`);
|
|
1482
|
+
});
|
|
1483
|
+
const transport = new TriggerChatTransport({
|
|
1484
|
+
task: "my-task",
|
|
1485
|
+
accessToken: "token",
|
|
1486
|
+
baseURL: "https://api.test.trigger.dev",
|
|
1487
|
+
onSessionChange,
|
|
1488
|
+
});
|
|
1489
|
+
const stream = await transport.sendMessages({
|
|
1490
|
+
trigger: "submit-message",
|
|
1491
|
+
chatId: "chat-end",
|
|
1492
|
+
messageId: undefined,
|
|
1493
|
+
messages: [createUserMessage("Hello")],
|
|
1494
|
+
abortSignal: undefined,
|
|
1495
|
+
});
|
|
1496
|
+
// Consume the stream fully
|
|
1497
|
+
const reader = stream.getReader();
|
|
1498
|
+
while (!(await reader.read()).done) { }
|
|
1499
|
+
// Session should have been created then deleted
|
|
1500
|
+
expect(onSessionChange).toHaveBeenCalledWith("chat-end", expect.objectContaining({
|
|
1501
|
+
runId: "run_end",
|
|
1502
|
+
}));
|
|
1503
|
+
expect(onSessionChange).toHaveBeenCalledWith("chat-end", null);
|
|
1504
|
+
});
|
|
1505
|
+
it("should be updatable via setOnSessionChange", async () => {
|
|
1506
|
+
const onSessionChange1 = vi.fn();
|
|
1507
|
+
const onSessionChange2 = vi.fn();
|
|
1508
|
+
global.fetch = vi.fn().mockImplementation(async (url) => {
|
|
1509
|
+
const urlStr = typeof url === "string" ? url : url.toString();
|
|
1510
|
+
if (urlStr.includes("/trigger")) {
|
|
1511
|
+
return new Response(JSON.stringify({ id: "run_update" }), {
|
|
1512
|
+
status: 200,
|
|
1513
|
+
headers: {
|
|
1514
|
+
"content-type": "application/json",
|
|
1515
|
+
"x-trigger-jwt": "pub_update",
|
|
1516
|
+
},
|
|
1517
|
+
});
|
|
1518
|
+
}
|
|
1519
|
+
if (urlStr.includes("/realtime/v1/streams/")) {
|
|
1520
|
+
const chunks = [
|
|
1521
|
+
...sampleChunks,
|
|
1522
|
+
{ type: "__trigger_turn_complete" },
|
|
1523
|
+
];
|
|
1524
|
+
return new Response(createSSEStream(sseEncode(chunks)), {
|
|
1525
|
+
status: 200,
|
|
1526
|
+
headers: {
|
|
1527
|
+
"content-type": "text/event-stream",
|
|
1528
|
+
"X-Stream-Version": "v1",
|
|
1529
|
+
},
|
|
1530
|
+
});
|
|
1531
|
+
}
|
|
1532
|
+
throw new Error(`Unexpected fetch URL: ${urlStr}`);
|
|
1533
|
+
});
|
|
1534
|
+
const transport = new TriggerChatTransport({
|
|
1535
|
+
task: "my-task",
|
|
1536
|
+
accessToken: "token",
|
|
1537
|
+
baseURL: "https://api.test.trigger.dev",
|
|
1538
|
+
onSessionChange: onSessionChange1,
|
|
1539
|
+
});
|
|
1540
|
+
// Update the callback before sending
|
|
1541
|
+
transport.setOnSessionChange(onSessionChange2);
|
|
1542
|
+
await transport.sendMessages({
|
|
1543
|
+
trigger: "submit-message",
|
|
1544
|
+
chatId: "chat-update",
|
|
1545
|
+
messageId: undefined,
|
|
1546
|
+
messages: [createUserMessage("Hello")],
|
|
1547
|
+
abortSignal: undefined,
|
|
1548
|
+
});
|
|
1549
|
+
// Only onSessionChange2 should have been called
|
|
1550
|
+
expect(onSessionChange1).not.toHaveBeenCalled();
|
|
1551
|
+
expect(onSessionChange2).toHaveBeenCalled();
|
|
1552
|
+
});
|
|
1553
|
+
});
|
|
1301
1554
|
});
|
|
1302
1555
|
//# sourceMappingURL=chat.test.js.map
|