@tanstack/ai-anthropic 0.8.6 → 0.8.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.
@@ -1,3 +1,4 @@
1
+ import { EventType } from '@tanstack/ai'
1
2
  import { BaseTextAdapter } from '@tanstack/ai/adapters'
2
3
  import { convertToolsToProviderFormat } from '../tools/tool-converter'
3
4
  import { validateTextProviderOptions } from '../text/text-provider-options'
@@ -48,11 +49,6 @@ import type {
48
49
  } from '../message-types'
49
50
  import type { AnthropicClientConfig } from '../utils'
50
51
 
51
- /** Cast an event object to StreamChunk. Adapters construct events with string
52
- * literal types which are structurally compatible with the EventType enum. */
53
- const asChunk = (chunk: Record<string, unknown>) =>
54
- chunk as unknown as StreamChunk
55
-
56
52
  /**
57
53
  * Configuration for Anthropic text adapter
58
54
  */
@@ -177,8 +173,8 @@ export class AnthropicTextAdapter<
177
173
  error,
178
174
  source: 'anthropic.chatStream',
179
175
  })
180
- yield asChunk({
181
- type: 'RUN_ERROR',
176
+ yield {
177
+ type: EventType.RUN_ERROR,
182
178
  model: options.model,
183
179
  timestamp: Date.now(),
184
180
  message: err.message || 'Unknown error occurred',
@@ -187,7 +183,7 @@ export class AnthropicTextAdapter<
187
183
  message: err.message || 'Unknown error occurred',
188
184
  code: err.code || String(err.status),
189
185
  },
190
- })
186
+ }
191
187
  }
192
188
  }
193
189
 
@@ -629,7 +625,6 @@ export class AnthropicTextAdapter<
629
625
  let accumulatedContent = ''
630
626
  let accumulatedThinking = ''
631
627
  let accumulatedSignature = ''
632
- const timestamp = Date.now()
633
628
  const toolCallsMap = new Map<
634
629
  number,
635
630
  { id: string; name: string; input: string; started: boolean }
@@ -657,13 +652,14 @@ export class AnthropicTextAdapter<
657
652
  // Emit RUN_STARTED on first event
658
653
  if (!hasEmittedRunStarted) {
659
654
  hasEmittedRunStarted = true
660
- yield asChunk({
661
- type: 'RUN_STARTED',
655
+ yield {
656
+ type: EventType.RUN_STARTED,
662
657
  runId,
663
658
  threadId,
664
659
  model,
665
- timestamp,
666
- })
660
+ timestamp: Date.now(),
661
+ parentRunId: options.parentRunId,
662
+ }
667
663
  }
668
664
 
669
665
  if (event.type === 'content_block_start') {
@@ -684,94 +680,94 @@ export class AnthropicTextAdapter<
684
680
  reasoningMessageId = genId()
685
681
 
686
682
  // Spec REASONING events
687
- yield asChunk({
688
- type: 'REASONING_START',
683
+ yield {
684
+ type: EventType.REASONING_START,
689
685
  messageId: reasoningMessageId,
690
686
  model,
691
- timestamp,
692
- })
693
- yield asChunk({
694
- type: 'REASONING_MESSAGE_START',
687
+ timestamp: Date.now(),
688
+ }
689
+ yield {
690
+ type: EventType.REASONING_MESSAGE_START,
695
691
  messageId: reasoningMessageId,
696
692
  role: 'reasoning' as const,
697
693
  model,
698
- timestamp,
699
- })
694
+ timestamp: Date.now(),
695
+ }
700
696
 
701
697
  // Legacy STEP events (kept during transition)
702
- yield asChunk({
703
- type: 'STEP_STARTED',
698
+ yield {
699
+ type: EventType.STEP_STARTED,
704
700
  stepName: stepId,
705
701
  stepId,
706
702
  model,
707
- timestamp,
703
+ timestamp: Date.now(),
708
704
  stepType: 'thinking',
709
- })
705
+ }
710
706
  }
711
707
  } else if (event.type === 'content_block_delta') {
712
708
  if (event.delta.type === 'text_delta') {
713
709
  // Close reasoning before text starts
714
710
  if (reasoningMessageId && !hasClosedReasoning) {
715
711
  hasClosedReasoning = true
716
- yield asChunk({
717
- type: 'REASONING_MESSAGE_END',
712
+ yield {
713
+ type: EventType.REASONING_MESSAGE_END,
718
714
  messageId: reasoningMessageId,
719
715
  model,
720
- timestamp,
721
- })
722
- yield asChunk({
723
- type: 'REASONING_END',
716
+ timestamp: Date.now(),
717
+ }
718
+ yield {
719
+ type: EventType.REASONING_END,
724
720
  messageId: reasoningMessageId,
725
721
  model,
726
- timestamp,
727
- })
722
+ timestamp: Date.now(),
723
+ }
728
724
  }
729
725
 
730
726
  // Emit TEXT_MESSAGE_START on first text content
731
727
  if (!hasEmittedTextMessageStart) {
732
728
  hasEmittedTextMessageStart = true
733
- yield asChunk({
734
- type: 'TEXT_MESSAGE_START',
729
+ yield {
730
+ type: EventType.TEXT_MESSAGE_START,
735
731
  messageId,
736
732
  model,
737
- timestamp,
733
+ timestamp: Date.now(),
738
734
  role: 'assistant',
739
- })
735
+ }
740
736
  }
741
737
 
742
738
  const delta = event.delta.text
743
739
  accumulatedContent += delta
744
- yield asChunk({
745
- type: 'TEXT_MESSAGE_CONTENT',
740
+ yield {
741
+ type: EventType.TEXT_MESSAGE_CONTENT,
746
742
  messageId,
747
743
  model,
748
- timestamp,
744
+ timestamp: Date.now(),
749
745
  delta,
750
746
  content: accumulatedContent,
751
- })
747
+ }
752
748
  } else if (event.delta.type === 'thinking_delta') {
753
749
  const delta = event.delta.thinking
754
750
  accumulatedThinking += delta
755
751
 
756
752
  // Spec REASONING content event
757
- yield asChunk({
758
- type: 'REASONING_MESSAGE_CONTENT',
753
+ yield {
754
+ type: EventType.REASONING_MESSAGE_CONTENT,
759
755
  messageId: reasoningMessageId!,
760
756
  delta,
761
757
  model,
762
- timestamp,
763
- })
758
+ timestamp: Date.now(),
759
+ }
764
760
 
765
761
  // Legacy STEP event
766
- yield asChunk({
767
- type: 'STEP_FINISHED',
762
+ yield {
763
+ type: EventType.STEP_FINISHED,
768
764
  stepName: stepId || genId(),
769
765
  stepId: stepId || genId(),
770
766
  model,
771
- timestamp,
767
+ timestamp: Date.now(),
772
768
  delta,
773
769
  content: accumulatedThinking,
774
- })
770
+ }
775
771
  } else if (
776
772
  (event.delta as { type: string }).type === 'signature_delta'
777
773
  ) {
@@ -783,43 +779,43 @@ export class AnthropicTextAdapter<
783
779
  // Emit TOOL_CALL_START on first args delta
784
780
  if (!existing.started) {
785
781
  existing.started = true
786
- yield asChunk({
787
- type: 'TOOL_CALL_START',
782
+ yield {
783
+ type: EventType.TOOL_CALL_START,
788
784
  toolCallId: existing.id,
789
785
  toolCallName: existing.name,
790
786
  toolName: existing.name,
791
787
  model,
792
- timestamp,
788
+ timestamp: Date.now(),
793
789
  index: currentToolIndex,
794
- })
790
+ }
795
791
  }
796
792
 
797
793
  existing.input += event.delta.partial_json
798
794
 
799
- yield asChunk({
800
- type: 'TOOL_CALL_ARGS',
795
+ yield {
796
+ type: EventType.TOOL_CALL_ARGS,
801
797
  toolCallId: existing.id,
802
798
  model,
803
- timestamp,
799
+ timestamp: Date.now(),
804
800
  delta: event.delta.partial_json,
805
801
  args: existing.input,
806
- })
802
+ }
807
803
  }
808
804
  }
809
805
  } else if (event.type === 'content_block_stop') {
810
806
  if (currentBlockType === 'thinking') {
811
807
  // Emit signature so it can be replayed in multi-turn context
812
808
  if (accumulatedSignature && stepId) {
813
- yield asChunk({
814
- type: 'STEP_FINISHED',
809
+ yield {
810
+ type: EventType.STEP_FINISHED,
815
811
  stepName: stepId,
816
812
  stepId,
817
813
  model,
818
- timestamp,
814
+ timestamp: Date.now(),
819
815
  delta: '',
820
816
  content: accumulatedThinking,
821
817
  signature: accumulatedSignature,
822
- })
818
+ }
823
819
  }
824
820
  } else if (currentBlockType === 'tool_use') {
825
821
  const existing = toolCallsMap.get(currentToolIndex)
@@ -827,15 +823,15 @@ export class AnthropicTextAdapter<
827
823
  // If tool call wasn't started yet (no args), start it now
828
824
  if (!existing.started) {
829
825
  existing.started = true
830
- yield asChunk({
831
- type: 'TOOL_CALL_START',
826
+ yield {
827
+ type: EventType.TOOL_CALL_START,
832
828
  toolCallId: existing.id,
833
829
  toolCallName: existing.name,
834
830
  toolName: existing.name,
835
831
  model,
836
- timestamp,
832
+ timestamp: Date.now(),
837
833
  index: currentToolIndex,
838
- })
834
+ }
839
835
  }
840
836
 
841
837
  // Emit TOOL_CALL_END
@@ -847,15 +843,15 @@ export class AnthropicTextAdapter<
847
843
  parsedInput = {}
848
844
  }
849
845
 
850
- yield asChunk({
851
- type: 'TOOL_CALL_END',
846
+ yield {
847
+ type: EventType.TOOL_CALL_END,
852
848
  toolCallId: existing.id,
853
849
  toolCallName: existing.name,
854
850
  toolName: existing.name,
855
851
  model,
856
- timestamp,
852
+ timestamp: Date.now(),
857
853
  input: parsedInput,
858
- })
854
+ }
859
855
 
860
856
  // Reset so a new TEXT_MESSAGE_START is emitted if text follows tool calls
861
857
  hasEmittedTextMessageStart = false
@@ -863,12 +859,12 @@ export class AnthropicTextAdapter<
863
859
  } else {
864
860
  // Emit TEXT_MESSAGE_END only for text blocks (not tool_use blocks)
865
861
  if (hasEmittedTextMessageStart && accumulatedContent) {
866
- yield asChunk({
867
- type: 'TEXT_MESSAGE_END',
862
+ yield {
863
+ type: EventType.TEXT_MESSAGE_END,
868
864
  messageId,
869
865
  model,
870
- timestamp,
871
- })
866
+ timestamp: Date.now(),
867
+ }
872
868
  }
873
869
  }
874
870
  currentBlockType = null
@@ -876,32 +872,32 @@ export class AnthropicTextAdapter<
876
872
  // Close reasoning events if still open
877
873
  if (reasoningMessageId && !hasClosedReasoning) {
878
874
  hasClosedReasoning = true
879
- yield asChunk({
880
- type: 'REASONING_MESSAGE_END',
875
+ yield {
876
+ type: EventType.REASONING_MESSAGE_END,
881
877
  messageId: reasoningMessageId,
882
878
  model,
883
- timestamp,
884
- })
885
- yield asChunk({
886
- type: 'REASONING_END',
879
+ timestamp: Date.now(),
880
+ }
881
+ yield {
882
+ type: EventType.REASONING_END,
887
883
  messageId: reasoningMessageId,
888
884
  model,
889
- timestamp,
890
- })
885
+ timestamp: Date.now(),
886
+ }
891
887
  }
892
888
 
893
889
  // Only emit RUN_FINISHED from message_stop if message_delta didn't already emit one.
894
890
  // message_delta carries the real stop_reason (tool_use, end_turn, etc.),
895
891
  // while message_stop is just a completion signal.
896
892
  if (!hasEmittedRunFinished) {
897
- yield asChunk({
898
- type: 'RUN_FINISHED',
893
+ yield {
894
+ type: EventType.RUN_FINISHED,
899
895
  runId,
900
896
  threadId,
901
897
  model,
902
- timestamp,
898
+ timestamp: Date.now(),
903
899
  finishReason: 'stop',
904
- })
900
+ }
905
901
  }
906
902
  } else if (event.type === 'message_delta') {
907
903
  if (event.delta.stop_reason) {
@@ -910,28 +906,28 @@ export class AnthropicTextAdapter<
910
906
  // Close reasoning events if still open
911
907
  if (reasoningMessageId && !hasClosedReasoning) {
912
908
  hasClosedReasoning = true
913
- yield asChunk({
914
- type: 'REASONING_MESSAGE_END',
909
+ yield {
910
+ type: EventType.REASONING_MESSAGE_END,
915
911
  messageId: reasoningMessageId,
916
912
  model,
917
- timestamp,
918
- })
919
- yield asChunk({
920
- type: 'REASONING_END',
913
+ timestamp: Date.now(),
914
+ }
915
+ yield {
916
+ type: EventType.REASONING_END,
921
917
  messageId: reasoningMessageId,
922
918
  model,
923
- timestamp,
924
- })
919
+ timestamp: Date.now(),
920
+ }
925
921
  }
926
922
 
927
923
  switch (event.delta.stop_reason) {
928
924
  case 'tool_use': {
929
- yield asChunk({
930
- type: 'RUN_FINISHED',
925
+ yield {
926
+ type: EventType.RUN_FINISHED,
931
927
  runId,
932
928
  threadId,
933
929
  model,
934
- timestamp,
930
+ timestamp: Date.now(),
935
931
  finishReason: 'tool_calls',
936
932
  usage: {
937
933
  promptTokens: event.usage.input_tokens || 0,
@@ -940,15 +936,14 @@ export class AnthropicTextAdapter<
940
936
  (event.usage.input_tokens || 0) +
941
937
  (event.usage.output_tokens || 0),
942
938
  },
943
- })
939
+ }
944
940
  break
945
941
  }
946
942
  case 'max_tokens': {
947
- yield asChunk({
948
- type: 'RUN_ERROR',
949
- runId,
943
+ yield {
944
+ type: EventType.RUN_ERROR,
950
945
  model,
951
- timestamp,
946
+ timestamp: Date.now(),
952
947
  message:
953
948
  'The response was cut off because the maximum token limit was reached.',
954
949
  code: 'max_tokens',
@@ -957,16 +952,16 @@ export class AnthropicTextAdapter<
957
952
  'The response was cut off because the maximum token limit was reached.',
958
953
  code: 'max_tokens',
959
954
  },
960
- })
955
+ }
961
956
  break
962
957
  }
963
958
  default: {
964
- yield asChunk({
965
- type: 'RUN_FINISHED',
959
+ yield {
960
+ type: EventType.RUN_FINISHED,
966
961
  runId,
967
962
  threadId,
968
963
  model,
969
- timestamp,
964
+ timestamp: Date.now(),
970
965
  finishReason: 'stop',
971
966
  usage: {
972
967
  promptTokens: event.usage.input_tokens || 0,
@@ -975,7 +970,7 @@ export class AnthropicTextAdapter<
975
970
  (event.usage.input_tokens || 0) +
976
971
  (event.usage.output_tokens || 0),
977
972
  },
978
- })
973
+ }
979
974
  }
980
975
  }
981
976
  }
@@ -988,18 +983,17 @@ export class AnthropicTextAdapter<
988
983
  error,
989
984
  source: 'anthropic.processAnthropicStream',
990
985
  })
991
- yield asChunk({
992
- type: 'RUN_ERROR',
993
- runId,
986
+ yield {
987
+ type: EventType.RUN_ERROR,
994
988
  model,
995
- timestamp,
989
+ timestamp: Date.now(),
996
990
  message: err.message || 'Unknown error occurred',
997
991
  code: err.code || String(err.status),
998
992
  error: {
999
993
  message: err.message || 'Unknown error occurred',
1000
994
  code: err.code || String(err.status),
1001
995
  },
1002
- })
996
+ }
1003
997
  }
1004
998
  }
1005
999
  }
package/src/index.ts CHANGED
@@ -11,13 +11,12 @@ export {
11
11
  type AnthropicTextProviderOptions,
12
12
  } from './adapters/text'
13
13
 
14
- // Summarize adapter - for text summarization
14
+ // Summarize - thin factory functions over @tanstack/ai's ChatStreamSummarizeAdapter
15
15
  export {
16
- AnthropicSummarizeAdapter,
17
16
  anthropicSummarize,
18
17
  createAnthropicSummarize,
19
18
  type AnthropicSummarizeConfig,
20
- type AnthropicSummarizeProviderOptions,
19
+ type AnthropicSummarizeModel,
21
20
  } from './adapters/summarize'
22
21
  // ============================================================================
23
22
  // Type Exports