@copilotkit/runtime 1.55.0-next.7 → 1.55.0-next.9

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.
@@ -1,13 +1,20 @@
1
1
  import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
2
2
  import { z } from "zod";
3
3
  import { BasicAgent, defineTool, type ToolDefinition } from "../index";
4
- import { EventType, type RunAgentInput } from "@ag-ui/client";
4
+ import {
5
+ EventType,
6
+ type BaseEvent,
7
+ type ReasoningStartEvent,
8
+ type RunAgentInput,
9
+ } from "@ag-ui/client";
5
10
  import { streamText } from "ai";
6
11
  import {
7
12
  mockStreamTextResponse,
8
13
  textStart,
9
14
  textDelta,
10
15
  finish,
16
+ abort,
17
+ error,
11
18
  collectEvents,
12
19
  toolCallStreamingStart,
13
20
  toolCallDelta,
@@ -1047,10 +1054,11 @@ describe("BasicAgent", () => {
1047
1054
 
1048
1055
  const events = await collectEvents(agent["run"](input));
1049
1056
 
1050
- const contentEvent = events.find(
1057
+ // Empty delta must NOT be emitted — EventSchemas rejects delta: ""
1058
+ const contentEvents = events.filter(
1051
1059
  (e: any) => e.type === EventType.REASONING_MESSAGE_CONTENT,
1052
1060
  );
1053
- expect(contentEvent).toMatchObject({ delta: "" });
1061
+ expect(contentEvents).toHaveLength(0);
1054
1062
 
1055
1063
  // Full lifecycle should still complete
1056
1064
  const eventTypes = events.map((e: any) => e.type);
@@ -1072,7 +1080,7 @@ describe("BasicAgent", () => {
1072
1080
  reasoningDelta("Deep thought"),
1073
1081
  reasoningEnd(),
1074
1082
  finish(),
1075
- ]) as any,
1083
+ ]),
1076
1084
  );
1077
1085
 
1078
1086
  const input: RunAgentInput = {
@@ -1102,6 +1110,448 @@ describe("BasicAgent", () => {
1102
1110
  });
1103
1111
  });
1104
1112
 
1113
+ it("should skip empty reasoning deltas and continue stream", async () => {
1114
+ const agent = new BasicAgent({
1115
+ model: "openai/gpt-4o",
1116
+ });
1117
+
1118
+ vi.mocked(streamText).mockReturnValue(
1119
+ mockStreamTextResponse([
1120
+ reasoningStart(),
1121
+ reasoningDelta(""),
1122
+ reasoningEnd(),
1123
+ finish(),
1124
+ ]),
1125
+ );
1126
+
1127
+ const input: RunAgentInput = {
1128
+ threadId: "thread1",
1129
+ runId: "run1",
1130
+ messages: [],
1131
+ tools: [],
1132
+ context: [],
1133
+ state: {},
1134
+ };
1135
+
1136
+ const events = await collectEvents(agent["run"](input));
1137
+
1138
+ // No REASONING_MESSAGE_CONTENT events — empty delta skipped
1139
+ const contentEvents = events.filter(
1140
+ (e) => e.type === EventType.REASONING_MESSAGE_CONTENT,
1141
+ );
1142
+ expect(contentEvents).toHaveLength(0);
1143
+
1144
+ // Stream still completes with RUN_FINISHED
1145
+ const eventTypes = events.map((e) => e.type);
1146
+ expect(eventTypes[eventTypes.length - 1]).toBe(EventType.RUN_FINISHED);
1147
+ });
1148
+
1149
+ it("should auto-close reasoning when SDK omits reasoning-end before tool call", async () => {
1150
+ const agent = new BasicAgent({
1151
+ model: "openai/gpt-4o",
1152
+ });
1153
+
1154
+ vi.mocked(streamText).mockReturnValue(
1155
+ mockStreamTextResponse([
1156
+ reasoningStart(),
1157
+ reasoningDelta("Thinking..."),
1158
+ // NO reasoningEnd() — simulates @ai-sdk/anthropic behaviour
1159
+ toolCallStreamingStart("call1", "testTool"),
1160
+ toolCallDelta("call1", '{"arg":"val"}'),
1161
+ toolCall("call1", "testTool", { arg: "val" }),
1162
+ toolResult("call1", "testTool", { result: "success" }),
1163
+ finish(),
1164
+ ]),
1165
+ );
1166
+
1167
+ const input: RunAgentInput = {
1168
+ threadId: "thread1",
1169
+ runId: "run1",
1170
+ messages: [],
1171
+ tools: [],
1172
+ context: [],
1173
+ state: {},
1174
+ };
1175
+
1176
+ const events = await collectEvents(agent["run"](input));
1177
+ const eventTypes = events.map((e) => e.type);
1178
+
1179
+ // REASONING_MESSAGE_END must appear before REASONING_END, which must appear before TOOL_CALL_START
1180
+ const reasoningMsgEndIdx = eventTypes.indexOf(
1181
+ EventType.REASONING_MESSAGE_END,
1182
+ );
1183
+ const reasoningEndIdx = eventTypes.indexOf(EventType.REASONING_END);
1184
+ const toolCallStartIdx = eventTypes.indexOf(EventType.TOOL_CALL_START);
1185
+ expect(reasoningMsgEndIdx).toBeGreaterThan(0);
1186
+ expect(reasoningEndIdx).toBeGreaterThan(reasoningMsgEndIdx);
1187
+ expect(reasoningEndIdx).toBeLessThan(toolCallStartIdx);
1188
+
1189
+ // Each close event must appear exactly once (guard against double-emit)
1190
+ expect(
1191
+ eventTypes.filter((t) => t === EventType.REASONING_MESSAGE_END),
1192
+ ).toHaveLength(1);
1193
+ expect(
1194
+ eventTypes.filter((t) => t === EventType.REASONING_END),
1195
+ ).toHaveLength(1);
1196
+
1197
+ // Stream still completes with RUN_FINISHED
1198
+ expect(eventTypes[eventTypes.length - 1]).toBe(EventType.RUN_FINISHED);
1199
+ });
1200
+
1201
+ it("should auto-close reasoning when SDK omits reasoning-end before text", async () => {
1202
+ const agent = new BasicAgent({
1203
+ model: "openai/gpt-4o",
1204
+ });
1205
+
1206
+ vi.mocked(streamText).mockReturnValue(
1207
+ mockStreamTextResponse([
1208
+ reasoningStart(),
1209
+ reasoningDelta("Let me think"),
1210
+ // NO reasoningEnd() — simulates @ai-sdk/anthropic behaviour
1211
+ textStart(),
1212
+ textDelta("Answer"),
1213
+ finish(),
1214
+ ]),
1215
+ );
1216
+
1217
+ const input: RunAgentInput = {
1218
+ threadId: "thread1",
1219
+ runId: "run1",
1220
+ messages: [],
1221
+ tools: [],
1222
+ context: [],
1223
+ state: {},
1224
+ };
1225
+
1226
+ const events = await collectEvents(agent["run"](input));
1227
+ const eventTypes = events.map((e) => e.type);
1228
+
1229
+ // REASONING_MESSAGE_END must appear before REASONING_END, which must appear before TEXT_MESSAGE_CHUNK
1230
+ const reasoningMsgEndIdx = eventTypes.indexOf(
1231
+ EventType.REASONING_MESSAGE_END,
1232
+ );
1233
+ const reasoningEndIdx = eventTypes.indexOf(EventType.REASONING_END);
1234
+ const textChunkIdx = eventTypes.indexOf(EventType.TEXT_MESSAGE_CHUNK);
1235
+ expect(reasoningMsgEndIdx).toBeGreaterThan(0);
1236
+ expect(reasoningEndIdx).toBeGreaterThan(reasoningMsgEndIdx);
1237
+ expect(reasoningEndIdx).toBeLessThan(textChunkIdx);
1238
+
1239
+ // Each close event must appear exactly once (guard against double-emit)
1240
+ expect(
1241
+ eventTypes.filter((t) => t === EventType.REASONING_MESSAGE_END),
1242
+ ).toHaveLength(1);
1243
+ expect(
1244
+ eventTypes.filter((t) => t === EventType.REASONING_END),
1245
+ ).toHaveLength(1);
1246
+
1247
+ // Stream still completes with RUN_FINISHED
1248
+ expect(eventTypes[eventTypes.length - 1]).toBe(EventType.RUN_FINISHED);
1249
+ });
1250
+
1251
+ it("should auto-close reasoning when SDK omits reasoning-end before finish", async () => {
1252
+ const agent = new BasicAgent({
1253
+ model: "openai/gpt-4o",
1254
+ });
1255
+
1256
+ vi.mocked(streamText).mockReturnValue(
1257
+ mockStreamTextResponse([
1258
+ reasoningStart(),
1259
+ reasoningDelta("Deep thought"),
1260
+ // NO reasoningEnd() — simulates @ai-sdk/anthropic behaviour
1261
+ finish(),
1262
+ ]),
1263
+ );
1264
+
1265
+ const input: RunAgentInput = {
1266
+ threadId: "thread1",
1267
+ runId: "run1",
1268
+ messages: [],
1269
+ tools: [],
1270
+ context: [],
1271
+ state: {},
1272
+ };
1273
+
1274
+ const events = await collectEvents(agent["run"](input));
1275
+ const eventTypes = events.map((e) => e.type);
1276
+
1277
+ // REASONING_MESSAGE_END must appear before REASONING_END (auto-closed by finish case)
1278
+ const reasoningMsgEndIdx = eventTypes.indexOf(
1279
+ EventType.REASONING_MESSAGE_END,
1280
+ );
1281
+ const reasoningEndIdx = eventTypes.indexOf(EventType.REASONING_END);
1282
+ expect(reasoningMsgEndIdx).toBeGreaterThan(0);
1283
+ expect(reasoningEndIdx).toBeGreaterThan(reasoningMsgEndIdx);
1284
+
1285
+ // Each close event must appear exactly once (guard against double-emit)
1286
+ expect(
1287
+ eventTypes.filter((t) => t === EventType.REASONING_MESSAGE_END),
1288
+ ).toHaveLength(1);
1289
+ expect(
1290
+ eventTypes.filter((t) => t === EventType.REASONING_END),
1291
+ ).toHaveLength(1);
1292
+
1293
+ // Stream still completes with RUN_FINISHED
1294
+ expect(eventTypes[eventTypes.length - 1]).toBe(EventType.RUN_FINISHED);
1295
+ });
1296
+
1297
+ it("should auto-close reasoning when stream aborts mid-reasoning", async () => {
1298
+ const agent = new BasicAgent({
1299
+ model: "openai/gpt-4o",
1300
+ });
1301
+
1302
+ vi.mocked(streamText).mockReturnValue(
1303
+ mockStreamTextResponse([
1304
+ reasoningStart(),
1305
+ reasoningDelta("Thinking..."),
1306
+ // NO reasoningEnd() — stream aborts before SDK can close reasoning
1307
+ abort(),
1308
+ ]),
1309
+ );
1310
+
1311
+ const input: RunAgentInput = {
1312
+ threadId: "thread1",
1313
+ runId: "run1",
1314
+ messages: [],
1315
+ tools: [],
1316
+ context: [],
1317
+ state: {},
1318
+ };
1319
+
1320
+ const events = await collectEvents(agent["run"](input));
1321
+ const eventTypes = events.map((e) => e.type);
1322
+
1323
+ // REASONING_MESSAGE_END must appear before REASONING_END, both before RUN_FINISHED
1324
+ const reasoningMsgEndIdx = eventTypes.indexOf(
1325
+ EventType.REASONING_MESSAGE_END,
1326
+ );
1327
+ const reasoningEndIdx = eventTypes.indexOf(EventType.REASONING_END);
1328
+ const runFinishedIdx = eventTypes.indexOf(EventType.RUN_FINISHED);
1329
+ expect(reasoningMsgEndIdx).toBeGreaterThan(0);
1330
+ expect(reasoningEndIdx).toBeGreaterThan(reasoningMsgEndIdx);
1331
+ expect(runFinishedIdx).toBeGreaterThan(reasoningEndIdx);
1332
+
1333
+ // Each close event must appear exactly once (guard against double-emit)
1334
+ expect(
1335
+ eventTypes.filter((t) => t === EventType.REASONING_MESSAGE_END),
1336
+ ).toHaveLength(1);
1337
+ expect(
1338
+ eventTypes.filter((t) => t === EventType.REASONING_END),
1339
+ ).toHaveLength(1);
1340
+
1341
+ // Stream still completes with RUN_FINISHED
1342
+ expect(eventTypes[eventTypes.length - 1]).toBe(EventType.RUN_FINISHED);
1343
+ });
1344
+
1345
+ it("should auto-close reasoning when stream errors mid-reasoning", async () => {
1346
+ const agent = new BasicAgent({
1347
+ model: "openai/gpt-4o",
1348
+ });
1349
+
1350
+ vi.mocked(streamText).mockReturnValue(
1351
+ mockStreamTextResponse([
1352
+ reasoningStart(),
1353
+ reasoningDelta("Thinking..."),
1354
+ // NO reasoningEnd() — stream errors before SDK can close reasoning
1355
+ error("stream failed"),
1356
+ ]),
1357
+ );
1358
+
1359
+ const input: RunAgentInput = {
1360
+ threadId: "thread1",
1361
+ runId: "run1",
1362
+ messages: [],
1363
+ tools: [],
1364
+ context: [],
1365
+ state: {},
1366
+ };
1367
+
1368
+ // subscriber.error() causes collectEvents to reject, so collect manually
1369
+ const events: BaseEvent[] = [];
1370
+ await new Promise<void>((resolve) => {
1371
+ agent["run"](input).subscribe({
1372
+ next: (e) => events.push(e),
1373
+ error: () => resolve(), // error is expected
1374
+ complete: () => resolve(),
1375
+ });
1376
+ });
1377
+
1378
+ const eventTypes = events.map((e) => e.type);
1379
+
1380
+ // REASONING_MESSAGE_END must appear before REASONING_END, both before RUN_ERROR
1381
+ const reasoningMsgEndIdx = eventTypes.indexOf(
1382
+ EventType.REASONING_MESSAGE_END,
1383
+ );
1384
+ const reasoningEndIdx = eventTypes.indexOf(EventType.REASONING_END);
1385
+ const runErrorIdx = eventTypes.indexOf(EventType.RUN_ERROR);
1386
+ expect(reasoningMsgEndIdx).toBeGreaterThan(0);
1387
+ expect(reasoningEndIdx).toBeGreaterThan(reasoningMsgEndIdx);
1388
+ expect(runErrorIdx).toBeGreaterThan(reasoningEndIdx);
1389
+
1390
+ // Each close event must appear exactly once (guard against double-emit)
1391
+ expect(
1392
+ eventTypes.filter((t) => t === EventType.REASONING_MESSAGE_END),
1393
+ ).toHaveLength(1);
1394
+ expect(
1395
+ eventTypes.filter((t) => t === EventType.REASONING_END),
1396
+ ).toHaveLength(1);
1397
+ });
1398
+
1399
+ it("should auto-close reasoning for consecutive blocks with no reasoning-end between them", async () => {
1400
+ const agent = new BasicAgent({
1401
+ model: "openai/gpt-4o",
1402
+ });
1403
+
1404
+ vi.mocked(streamText).mockReturnValue(
1405
+ mockStreamTextResponse([
1406
+ reasoningStart(),
1407
+ reasoningDelta("First thought"),
1408
+ // NO reasoningEnd() — second block starts immediately
1409
+ reasoningStart(),
1410
+ reasoningDelta("Second thought"),
1411
+ reasoningEnd(),
1412
+ finish(),
1413
+ ]),
1414
+ );
1415
+
1416
+ const input: RunAgentInput = {
1417
+ threadId: "thread1",
1418
+ runId: "run1",
1419
+ messages: [],
1420
+ tools: [],
1421
+ context: [],
1422
+ state: {},
1423
+ };
1424
+
1425
+ const events = await collectEvents(agent["run"](input));
1426
+ const eventTypes = events.map((e) => e.type);
1427
+
1428
+ // Both reasoning blocks must be properly closed — two complete lifecycles
1429
+ expect(
1430
+ eventTypes.filter((t) => t === EventType.REASONING_MESSAGE_END),
1431
+ ).toHaveLength(2);
1432
+ expect(
1433
+ eventTypes.filter((t) => t === EventType.REASONING_END),
1434
+ ).toHaveLength(2);
1435
+
1436
+ // First block's REASONING_END must appear before second block's REASONING_START
1437
+ const firstReasoningEndIdx = eventTypes.indexOf(EventType.REASONING_END);
1438
+ const secondReasoningStartIdx = eventTypes.lastIndexOf(
1439
+ EventType.REASONING_START,
1440
+ );
1441
+ expect(firstReasoningEndIdx).toBeLessThan(secondReasoningStartIdx);
1442
+
1443
+ // The two blocks must use distinct messageIds
1444
+ const startEvents = events.filter(
1445
+ (e): e is ReasoningStartEvent => e.type === EventType.REASONING_START,
1446
+ );
1447
+ expect(startEvents).toHaveLength(2);
1448
+ expect(startEvents[0].messageId).not.toBe(startEvents[1].messageId);
1449
+
1450
+ expect(eventTypes[eventTypes.length - 1]).toBe(EventType.RUN_FINISHED);
1451
+ });
1452
+
1453
+ it("should close reasoning when an exception is thrown mid-stream", async () => {
1454
+ const agent = new BasicAgent({
1455
+ model: "openai/gpt-4o",
1456
+ });
1457
+
1458
+ // Simulate the fullStream generator throwing mid-iteration (not a stream error event)
1459
+ const throwingStream = {
1460
+ fullStream: (async function* () {
1461
+ yield reasoningStart();
1462
+ yield reasoningDelta("Thinking...");
1463
+ throw new Error("unexpected network failure");
1464
+ })(),
1465
+ };
1466
+ vi.mocked(streamText).mockReturnValue(
1467
+ throwingStream as unknown as ReturnType<typeof streamText>,
1468
+ );
1469
+
1470
+ const input: RunAgentInput = {
1471
+ threadId: "thread1",
1472
+ runId: "run1",
1473
+ messages: [],
1474
+ tools: [],
1475
+ context: [],
1476
+ state: {},
1477
+ };
1478
+
1479
+ // subscriber.error() causes collectEvents to reject, so collect manually
1480
+ const events: BaseEvent[] = [];
1481
+ await new Promise<void>((resolve) => {
1482
+ agent["run"](input).subscribe({
1483
+ next: (e) => events.push(e),
1484
+ error: () => resolve(), // error is expected
1485
+ complete: () => resolve(),
1486
+ });
1487
+ });
1488
+
1489
+ const eventTypes = events.map((e) => e.type);
1490
+
1491
+ // Reasoning must be closed before RUN_ERROR despite the exception path
1492
+ const reasoningMsgEndIdx = eventTypes.indexOf(
1493
+ EventType.REASONING_MESSAGE_END,
1494
+ );
1495
+ const reasoningEndIdx = eventTypes.indexOf(EventType.REASONING_END);
1496
+ const runErrorIdx = eventTypes.indexOf(EventType.RUN_ERROR);
1497
+ expect(reasoningMsgEndIdx).toBeGreaterThan(0);
1498
+ expect(reasoningEndIdx).toBeGreaterThan(reasoningMsgEndIdx);
1499
+ expect(runErrorIdx).toBeGreaterThan(reasoningEndIdx);
1500
+
1501
+ expect(
1502
+ eventTypes.filter((t) => t === EventType.REASONING_MESSAGE_END),
1503
+ ).toHaveLength(1);
1504
+ expect(
1505
+ eventTypes.filter((t) => t === EventType.REASONING_END),
1506
+ ).toHaveLength(1);
1507
+ });
1508
+
1509
+ it("should close reasoning and emit RUN_FINISHED when stream exhausts without terminal event", async () => {
1510
+ const agent = new BasicAgent({
1511
+ model: "openai/gpt-4o",
1512
+ });
1513
+
1514
+ // Stream ends with no finish/abort/error — exercises !terminalEventEmitted fallback
1515
+ vi.mocked(streamText).mockReturnValue(
1516
+ mockStreamTextResponse([
1517
+ reasoningStart(),
1518
+ reasoningDelta("Thinking..."),
1519
+ // deliberate: no finish(), no abort(), no error()
1520
+ ]),
1521
+ );
1522
+
1523
+ const input: RunAgentInput = {
1524
+ threadId: "thread1",
1525
+ runId: "run1",
1526
+ messages: [],
1527
+ tools: [],
1528
+ context: [],
1529
+ state: {},
1530
+ };
1531
+
1532
+ const events = await collectEvents(agent["run"](input));
1533
+ const eventTypes = events.map((e) => e.type);
1534
+
1535
+ // Reasoning must be closed before RUN_FINISHED via fallback
1536
+ const reasoningMsgEndIdx = eventTypes.indexOf(
1537
+ EventType.REASONING_MESSAGE_END,
1538
+ );
1539
+ const reasoningEndIdx = eventTypes.indexOf(EventType.REASONING_END);
1540
+ const runFinishedIdx = eventTypes.indexOf(EventType.RUN_FINISHED);
1541
+ expect(reasoningMsgEndIdx).toBeGreaterThan(0);
1542
+ expect(reasoningEndIdx).toBeGreaterThan(reasoningMsgEndIdx);
1543
+ expect(runFinishedIdx).toBeGreaterThan(reasoningEndIdx);
1544
+
1545
+ expect(
1546
+ eventTypes.filter((t) => t === EventType.REASONING_MESSAGE_END),
1547
+ ).toHaveLength(1);
1548
+ expect(
1549
+ eventTypes.filter((t) => t === EventType.REASONING_END),
1550
+ ).toHaveLength(1);
1551
+
1552
+ expect(eventTypes[eventTypes.length - 1]).toBe(EventType.RUN_FINISHED);
1553
+ });
1554
+
1105
1555
  it("should handle reasoning interleaved with tool calls", async () => {
1106
1556
  const agent = new BasicAgent({
1107
1557
  model: "openai/gpt-4o",
@@ -1130,7 +1580,7 @@ describe("BasicAgent", () => {
1130
1580
  };
1131
1581
 
1132
1582
  const events = await collectEvents(agent["run"](input));
1133
- const eventTypes = events.map((e: any) => e.type);
1583
+ const eventTypes = events.map((e) => e.type);
1134
1584
 
1135
1585
  // Reasoning events precede tool call events
1136
1586
  const reasoningEndIdx = eventTypes.indexOf(EventType.REASONING_END);
@@ -2,22 +2,28 @@
2
2
  * Test helpers for mocking streamText responses
3
3
  */
4
4
 
5
+ import type { streamText } from "ai";
6
+ import type { Observable } from "rxjs";
7
+ import type { BaseEvent } from "@ag-ui/client";
8
+
5
9
  export interface MockStreamEvent {
6
10
  type: string;
7
- [key: string]: any;
11
+ [key: string]: unknown;
8
12
  }
9
13
 
10
14
  /**
11
- * Creates a mock streamText response with controlled events
15
+ * Creates a mock streamText response with controlled events.
12
16
  */
13
- export function mockStreamTextResponse(events: MockStreamEvent[]) {
17
+ export function mockStreamTextResponse(
18
+ events: MockStreamEvent[],
19
+ ): ReturnType<typeof streamText> {
14
20
  return {
15
21
  fullStream: (async function* () {
16
22
  for (const event of events) {
17
23
  yield event;
18
24
  }
19
25
  })(),
20
- };
26
+ } as unknown as ReturnType<typeof streamText>;
21
27
  }
22
28
 
23
29
  /**
@@ -93,7 +99,7 @@ export function toolCall(
93
99
  export function toolResult(
94
100
  toolCallId: string,
95
101
  toolName: string,
96
- output: any,
102
+ output: unknown,
97
103
  ): MockStreamEvent {
98
104
  return {
99
105
  type: "tool-result",
@@ -145,6 +151,15 @@ export function finish(): MockStreamEvent {
145
151
  };
146
152
  }
147
153
 
154
+ /**
155
+ * Helper to create an abort event
156
+ */
157
+ export function abort(): MockStreamEvent {
158
+ return {
159
+ type: "abort",
160
+ };
161
+ }
162
+
148
163
  /**
149
164
  * Helper to create an error event
150
165
  */
@@ -156,16 +171,16 @@ export function error(errorMessage: string): MockStreamEvent {
156
171
  }
157
172
 
158
173
  /**
159
- * Collects all events from an Observable into an array
174
+ * Collects all events from an Observable<BaseEvent> into an array.
160
175
  */
161
- export async function collectEvents<T>(observable: {
162
- subscribe: (observer: any) => any;
163
- }): Promise<T[]> {
176
+ export async function collectEvents(
177
+ observable: Observable<BaseEvent>,
178
+ ): Promise<BaseEvent[]> {
164
179
  return new Promise((resolve, reject) => {
165
- const events: T[] = [];
180
+ const events: BaseEvent[] = [];
166
181
  const subscription = observable.subscribe({
167
- next: (event: T) => events.push(event),
168
- error: (err: any) => reject(err),
182
+ next: (event) => events.push(event),
183
+ error: (err: unknown) => reject(err),
169
184
  complete: () => resolve(events),
170
185
  });
171
186