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

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/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @copilotkit/runtime
2
2
 
3
+ ## 1.55.0-next.8
4
+
5
+ ### Patch Changes
6
+
7
+ - 8aafcbe: fix(agent): harden BuiltInAgent reasoning lifecycle
8
+ - Skip empty reasoning deltas (violates @ag-ui/core schema)
9
+ - Auto-close reasoning lifecycle when SDK omits reasoning-end (on consecutive-start, phase transitions, abort, error, and fallback paths)
10
+ - Make reasoning-end idempotent to prevent duplicate close events when auto-close already fired
11
+ - Regenerate reasoningMessageId for consecutive reasoning blocks when SDK provides no id
12
+ - Close reasoning in outer catch block so exceptions mid-reasoning emit proper lifecycle events
13
+ - @copilotkit/shared@1.55.0-next.8
14
+
3
15
  ## 1.55.0-next.7
4
16
 
5
17
  ### Minor Changes
@@ -320,6 +320,23 @@ This is state from the application that you can edit by calling AGUISendStateSna
320
320
  const abortController = new AbortController();
321
321
  this.abortController = abortController;
322
322
  let terminalEventEmitted = false;
323
+ let messageId = (0, crypto.randomUUID)();
324
+ let reasoningMessageId = (0, crypto.randomUUID)();
325
+ let isInReasoning = false;
326
+ const closeReasoningIfOpen = () => {
327
+ if (!isInReasoning) return;
328
+ isInReasoning = false;
329
+ const reasoningMsgEnd = {
330
+ type: _ag_ui_client.EventType.REASONING_MESSAGE_END,
331
+ messageId: reasoningMessageId
332
+ };
333
+ subscriber.next(reasoningMsgEnd);
334
+ const reasoningEnd = {
335
+ type: _ag_ui_client.EventType.REASONING_END,
336
+ messageId: reasoningMessageId
337
+ };
338
+ subscriber.next(reasoningEnd);
339
+ };
323
340
  try {
324
341
  streamTextParams.tools = {
325
342
  ...streamTextParams.tools,
@@ -377,8 +394,6 @@ This is state from the application that you can edit by calling AGUISendStateSna
377
394
  ...streamTextParams,
378
395
  abortSignal: abortController.signal
379
396
  });
380
- let messageId = (0, crypto.randomUUID)();
381
- let reasoningMessageId = (0, crypto.randomUUID)();
382
397
  const toolCallStates = /* @__PURE__ */ new Map();
383
398
  const ensureToolCallState = (toolCallId) => {
384
399
  let state = toolCallStates.get(toolCallId);
@@ -392,194 +407,189 @@ This is state from the application that you can edit by calling AGUISendStateSna
392
407
  }
393
408
  return state;
394
409
  };
395
- for await (const part of response.fullStream) switch (part.type) {
396
- case "abort": {
397
- const abortEndEvent = {
398
- type: _ag_ui_client.EventType.RUN_FINISHED,
399
- threadId: input.threadId,
400
- runId: input.runId
401
- };
402
- subscriber.next(abortEndEvent);
403
- terminalEventEmitted = true;
404
- subscriber.complete();
405
- break;
406
- }
407
- case "reasoning-start": {
408
- const providedId = "id" in part ? part.id : void 0;
409
- if (providedId && providedId !== "0") reasoningMessageId = providedId;
410
- const reasoningStartEvent = {
411
- type: _ag_ui_client.EventType.REASONING_START,
412
- messageId: reasoningMessageId
413
- };
414
- subscriber.next(reasoningStartEvent);
415
- const reasoningMessageStart = {
416
- type: _ag_ui_client.EventType.REASONING_MESSAGE_START,
417
- messageId: reasoningMessageId,
418
- role: "reasoning"
419
- };
420
- subscriber.next(reasoningMessageStart);
421
- break;
422
- }
423
- case "reasoning-delta": {
424
- const reasoningDeltaEvent = {
425
- type: _ag_ui_client.EventType.REASONING_MESSAGE_CONTENT,
426
- messageId: reasoningMessageId,
427
- delta: ("text" in part ? part.text : part.delta) ?? ""
428
- };
429
- subscriber.next(reasoningDeltaEvent);
430
- break;
431
- }
432
- case "reasoning-end": {
433
- const reasoningMessageEnd = {
434
- type: _ag_ui_client.EventType.REASONING_MESSAGE_END,
435
- messageId: reasoningMessageId
436
- };
437
- subscriber.next(reasoningMessageEnd);
438
- const reasoningEndEvent = {
439
- type: _ag_ui_client.EventType.REASONING_END,
440
- messageId: reasoningMessageId
441
- };
442
- subscriber.next(reasoningEndEvent);
443
- break;
444
- }
445
- case "tool-input-start": {
446
- const toolCallId = part.id;
447
- const state = ensureToolCallState(toolCallId);
448
- state.toolName = part.toolName;
449
- if (!state.started) {
450
- state.started = true;
451
- const startEvent = {
452
- type: _ag_ui_client.EventType.TOOL_CALL_START,
453
- parentMessageId: messageId,
454
- toolCallId,
455
- toolCallName: part.toolName
410
+ for await (const part of response.fullStream) {
411
+ if (part.type !== "reasoning-delta") closeReasoningIfOpen();
412
+ switch (part.type) {
413
+ case "abort": {
414
+ const abortEndEvent = {
415
+ type: _ag_ui_client.EventType.RUN_FINISHED,
416
+ threadId: input.threadId,
417
+ runId: input.runId
456
418
  };
457
- subscriber.next(startEvent);
419
+ subscriber.next(abortEndEvent);
420
+ terminalEventEmitted = true;
421
+ subscriber.complete();
422
+ break;
458
423
  }
459
- break;
460
- }
461
- case "tool-input-delta": {
462
- const toolCallId = part.id;
463
- const state = ensureToolCallState(toolCallId);
464
- state.hasArgsDelta = true;
465
- const argsEvent = {
466
- type: _ag_ui_client.EventType.TOOL_CALL_ARGS,
467
- toolCallId,
468
- delta: part.delta
469
- };
470
- subscriber.next(argsEvent);
471
- break;
472
- }
473
- case "tool-input-end": break;
474
- case "text-start": {
475
- const providedId = "id" in part ? part.id : void 0;
476
- messageId = providedId && providedId !== "0" ? providedId : (0, crypto.randomUUID)();
477
- break;
478
- }
479
- case "text-delta": {
480
- const textDelta = "text" in part ? part.text : "";
481
- const textEvent = {
482
- type: _ag_ui_client.EventType.TEXT_MESSAGE_CHUNK,
483
- role: "assistant",
484
- messageId,
485
- delta: textDelta
486
- };
487
- subscriber.next(textEvent);
488
- break;
489
- }
490
- case "tool-call": {
491
- const toolCallId = part.toolCallId;
492
- const state = ensureToolCallState(toolCallId);
493
- state.toolName = part.toolName ?? state.toolName;
494
- if (!state.started) {
495
- state.started = true;
496
- const startEvent = {
497
- type: _ag_ui_client.EventType.TOOL_CALL_START,
498
- parentMessageId: messageId,
499
- toolCallId,
500
- toolCallName: part.toolName
424
+ case "reasoning-start": {
425
+ const providedId = "id" in part ? part.id : void 0;
426
+ reasoningMessageId = providedId && providedId !== "0" ? providedId : (0, crypto.randomUUID)();
427
+ const reasoningStartEvent = {
428
+ type: _ag_ui_client.EventType.REASONING_START,
429
+ messageId: reasoningMessageId
430
+ };
431
+ subscriber.next(reasoningStartEvent);
432
+ const reasoningMessageStart = {
433
+ type: _ag_ui_client.EventType.REASONING_MESSAGE_START,
434
+ messageId: reasoningMessageId,
435
+ role: "reasoning"
436
+ };
437
+ subscriber.next(reasoningMessageStart);
438
+ isInReasoning = true;
439
+ break;
440
+ }
441
+ case "reasoning-delta": {
442
+ const delta = part.text ?? "";
443
+ if (!delta) break;
444
+ const reasoningDeltaEvent = {
445
+ type: _ag_ui_client.EventType.REASONING_MESSAGE_CONTENT,
446
+ messageId: reasoningMessageId,
447
+ delta
501
448
  };
502
- subscriber.next(startEvent);
449
+ subscriber.next(reasoningDeltaEvent);
450
+ break;
503
451
  }
504
- if (!state.hasArgsDelta && "input" in part && part.input !== void 0) {
505
- let serializedInput = "";
506
- if (typeof part.input === "string") serializedInput = part.input;
507
- else try {
508
- serializedInput = JSON.stringify(part.input);
509
- } catch {
510
- serializedInput = String(part.input);
452
+ case "reasoning-end": break;
453
+ case "tool-input-start": {
454
+ const toolCallId = part.id;
455
+ const state = ensureToolCallState(toolCallId);
456
+ state.toolName = part.toolName;
457
+ if (!state.started) {
458
+ state.started = true;
459
+ const startEvent = {
460
+ type: _ag_ui_client.EventType.TOOL_CALL_START,
461
+ parentMessageId: messageId,
462
+ toolCallId,
463
+ toolCallName: part.toolName
464
+ };
465
+ subscriber.next(startEvent);
511
466
  }
512
- if (serializedInput.length > 0) {
513
- const argsEvent = {
514
- type: _ag_ui_client.EventType.TOOL_CALL_ARGS,
467
+ break;
468
+ }
469
+ case "tool-input-delta": {
470
+ const toolCallId = part.id;
471
+ const state = ensureToolCallState(toolCallId);
472
+ state.hasArgsDelta = true;
473
+ const argsEvent = {
474
+ type: _ag_ui_client.EventType.TOOL_CALL_ARGS,
475
+ toolCallId,
476
+ delta: part.delta
477
+ };
478
+ subscriber.next(argsEvent);
479
+ break;
480
+ }
481
+ case "tool-input-end": break;
482
+ case "text-start": {
483
+ const providedId = "id" in part ? part.id : void 0;
484
+ messageId = providedId && providedId !== "0" ? providedId : (0, crypto.randomUUID)();
485
+ break;
486
+ }
487
+ case "text-delta": {
488
+ const textDelta = "text" in part ? part.text : "";
489
+ const textEvent = {
490
+ type: _ag_ui_client.EventType.TEXT_MESSAGE_CHUNK,
491
+ role: "assistant",
492
+ messageId,
493
+ delta: textDelta
494
+ };
495
+ subscriber.next(textEvent);
496
+ break;
497
+ }
498
+ case "tool-call": {
499
+ const toolCallId = part.toolCallId;
500
+ const state = ensureToolCallState(toolCallId);
501
+ state.toolName = part.toolName ?? state.toolName;
502
+ if (!state.started) {
503
+ state.started = true;
504
+ const startEvent = {
505
+ type: _ag_ui_client.EventType.TOOL_CALL_START,
506
+ parentMessageId: messageId,
515
507
  toolCallId,
516
- delta: serializedInput
508
+ toolCallName: part.toolName
517
509
  };
518
- subscriber.next(argsEvent);
519
- state.hasArgsDelta = true;
510
+ subscriber.next(startEvent);
520
511
  }
512
+ if (!state.hasArgsDelta && "input" in part && part.input !== void 0) {
513
+ let serializedInput = "";
514
+ if (typeof part.input === "string") serializedInput = part.input;
515
+ else try {
516
+ serializedInput = JSON.stringify(part.input);
517
+ } catch {
518
+ serializedInput = String(part.input);
519
+ }
520
+ if (serializedInput.length > 0) {
521
+ const argsEvent = {
522
+ type: _ag_ui_client.EventType.TOOL_CALL_ARGS,
523
+ toolCallId,
524
+ delta: serializedInput
525
+ };
526
+ subscriber.next(argsEvent);
527
+ state.hasArgsDelta = true;
528
+ }
529
+ }
530
+ if (!state.ended) {
531
+ state.ended = true;
532
+ const endEvent = {
533
+ type: _ag_ui_client.EventType.TOOL_CALL_END,
534
+ toolCallId
535
+ };
536
+ subscriber.next(endEvent);
537
+ }
538
+ break;
521
539
  }
522
- if (!state.ended) {
523
- state.ended = true;
524
- const endEvent = {
525
- type: _ag_ui_client.EventType.TOOL_CALL_END,
526
- toolCallId
540
+ case "tool-result": {
541
+ const toolResult = "output" in part ? part.output : null;
542
+ const toolName = "toolName" in part ? part.toolName : "";
543
+ toolCallStates.delete(part.toolCallId);
544
+ if (toolName === "AGUISendStateSnapshot" && toolResult && typeof toolResult === "object") {
545
+ const stateSnapshotEvent = {
546
+ type: _ag_ui_client.EventType.STATE_SNAPSHOT,
547
+ snapshot: toolResult.snapshot
548
+ };
549
+ subscriber.next(stateSnapshotEvent);
550
+ } else if (toolName === "AGUISendStateDelta" && toolResult && typeof toolResult === "object") {
551
+ const stateDeltaEvent = {
552
+ type: _ag_ui_client.EventType.STATE_DELTA,
553
+ delta: toolResult.delta
554
+ };
555
+ subscriber.next(stateDeltaEvent);
556
+ }
557
+ const resultEvent = {
558
+ type: _ag_ui_client.EventType.TOOL_CALL_RESULT,
559
+ role: "tool",
560
+ messageId: (0, crypto.randomUUID)(),
561
+ toolCallId: part.toolCallId,
562
+ content: JSON.stringify(toolResult)
527
563
  };
528
- subscriber.next(endEvent);
564
+ subscriber.next(resultEvent);
565
+ break;
529
566
  }
530
- break;
531
- }
532
- case "tool-result": {
533
- const toolResult = "output" in part ? part.output : null;
534
- const toolName = "toolName" in part ? part.toolName : "";
535
- toolCallStates.delete(part.toolCallId);
536
- if (toolName === "AGUISendStateSnapshot" && toolResult && typeof toolResult === "object") {
537
- const stateSnapshotEvent = {
538
- type: _ag_ui_client.EventType.STATE_SNAPSHOT,
539
- snapshot: toolResult.snapshot
567
+ case "finish": {
568
+ const finishedEvent = {
569
+ type: _ag_ui_client.EventType.RUN_FINISHED,
570
+ threadId: input.threadId,
571
+ runId: input.runId
540
572
  };
541
- subscriber.next(stateSnapshotEvent);
542
- } else if (toolName === "AGUISendStateDelta" && toolResult && typeof toolResult === "object") {
543
- const stateDeltaEvent = {
544
- type: _ag_ui_client.EventType.STATE_DELTA,
545
- delta: toolResult.delta
573
+ subscriber.next(finishedEvent);
574
+ terminalEventEmitted = true;
575
+ subscriber.complete();
576
+ break;
577
+ }
578
+ case "error": {
579
+ if (abortController.signal.aborted) break;
580
+ const runErrorEvent = {
581
+ type: _ag_ui_client.EventType.RUN_ERROR,
582
+ message: part.error + ""
546
583
  };
547
- subscriber.next(stateDeltaEvent);
584
+ subscriber.next(runErrorEvent);
585
+ terminalEventEmitted = true;
586
+ subscriber.error(part.error);
587
+ break;
548
588
  }
549
- const resultEvent = {
550
- type: _ag_ui_client.EventType.TOOL_CALL_RESULT,
551
- role: "tool",
552
- messageId: (0, crypto.randomUUID)(),
553
- toolCallId: part.toolCallId,
554
- content: JSON.stringify(toolResult)
555
- };
556
- subscriber.next(resultEvent);
557
- break;
558
- }
559
- case "finish": {
560
- const finishedEvent = {
561
- type: _ag_ui_client.EventType.RUN_FINISHED,
562
- threadId: input.threadId,
563
- runId: input.runId
564
- };
565
- subscriber.next(finishedEvent);
566
- terminalEventEmitted = true;
567
- subscriber.complete();
568
- break;
569
- }
570
- case "error": {
571
- if (abortController.signal.aborted) break;
572
- const runErrorEvent = {
573
- type: _ag_ui_client.EventType.RUN_ERROR,
574
- message: part.error + ""
575
- };
576
- subscriber.next(runErrorEvent);
577
- terminalEventEmitted = true;
578
- subscriber.error(part.error);
579
- break;
580
589
  }
581
590
  }
582
591
  if (!terminalEventEmitted) {
592
+ closeReasoningIfOpen();
583
593
  if (abortController.signal.aborted) {} else {
584
594
  const finishedEvent = {
585
595
  type: _ag_ui_client.EventType.RUN_FINISHED,
@@ -592,6 +602,7 @@ This is state from the application that you can edit by calling AGUISendStateSna
592
602
  subscriber.complete();
593
603
  }
594
604
  } catch (error) {
605
+ closeReasoningIfOpen();
595
606
  if (abortController.signal.aborted) subscriber.complete();
596
607
  else {
597
608
  const runErrorEvent = {