@tanstack/ai-anthropic 0.8.6 → 0.8.7

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,13 @@ 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
+ }
667
662
  }
668
663
 
669
664
  if (event.type === 'content_block_start') {
@@ -684,94 +679,94 @@ export class AnthropicTextAdapter<
684
679
  reasoningMessageId = genId()
685
680
 
686
681
  // Spec REASONING events
687
- yield asChunk({
688
- type: 'REASONING_START',
682
+ yield {
683
+ type: EventType.REASONING_START,
689
684
  messageId: reasoningMessageId,
690
685
  model,
691
- timestamp,
692
- })
693
- yield asChunk({
694
- type: 'REASONING_MESSAGE_START',
686
+ timestamp: Date.now(),
687
+ }
688
+ yield {
689
+ type: EventType.REASONING_MESSAGE_START,
695
690
  messageId: reasoningMessageId,
696
691
  role: 'reasoning' as const,
697
692
  model,
698
- timestamp,
699
- })
693
+ timestamp: Date.now(),
694
+ }
700
695
 
701
696
  // Legacy STEP events (kept during transition)
702
- yield asChunk({
703
- type: 'STEP_STARTED',
697
+ yield {
698
+ type: EventType.STEP_STARTED,
704
699
  stepName: stepId,
705
700
  stepId,
706
701
  model,
707
- timestamp,
702
+ timestamp: Date.now(),
708
703
  stepType: 'thinking',
709
- })
704
+ }
710
705
  }
711
706
  } else if (event.type === 'content_block_delta') {
712
707
  if (event.delta.type === 'text_delta') {
713
708
  // Close reasoning before text starts
714
709
  if (reasoningMessageId && !hasClosedReasoning) {
715
710
  hasClosedReasoning = true
716
- yield asChunk({
717
- type: 'REASONING_MESSAGE_END',
711
+ yield {
712
+ type: EventType.REASONING_MESSAGE_END,
718
713
  messageId: reasoningMessageId,
719
714
  model,
720
- timestamp,
721
- })
722
- yield asChunk({
723
- type: 'REASONING_END',
715
+ timestamp: Date.now(),
716
+ }
717
+ yield {
718
+ type: EventType.REASONING_END,
724
719
  messageId: reasoningMessageId,
725
720
  model,
726
- timestamp,
727
- })
721
+ timestamp: Date.now(),
722
+ }
728
723
  }
729
724
 
730
725
  // Emit TEXT_MESSAGE_START on first text content
731
726
  if (!hasEmittedTextMessageStart) {
732
727
  hasEmittedTextMessageStart = true
733
- yield asChunk({
734
- type: 'TEXT_MESSAGE_START',
728
+ yield {
729
+ type: EventType.TEXT_MESSAGE_START,
735
730
  messageId,
736
731
  model,
737
- timestamp,
732
+ timestamp: Date.now(),
738
733
  role: 'assistant',
739
- })
734
+ }
740
735
  }
741
736
 
742
737
  const delta = event.delta.text
743
738
  accumulatedContent += delta
744
- yield asChunk({
745
- type: 'TEXT_MESSAGE_CONTENT',
739
+ yield {
740
+ type: EventType.TEXT_MESSAGE_CONTENT,
746
741
  messageId,
747
742
  model,
748
- timestamp,
743
+ timestamp: Date.now(),
749
744
  delta,
750
745
  content: accumulatedContent,
751
- })
746
+ }
752
747
  } else if (event.delta.type === 'thinking_delta') {
753
748
  const delta = event.delta.thinking
754
749
  accumulatedThinking += delta
755
750
 
756
751
  // Spec REASONING content event
757
- yield asChunk({
758
- type: 'REASONING_MESSAGE_CONTENT',
752
+ yield {
753
+ type: EventType.REASONING_MESSAGE_CONTENT,
759
754
  messageId: reasoningMessageId!,
760
755
  delta,
761
756
  model,
762
- timestamp,
763
- })
757
+ timestamp: Date.now(),
758
+ }
764
759
 
765
760
  // Legacy STEP event
766
- yield asChunk({
767
- type: 'STEP_FINISHED',
761
+ yield {
762
+ type: EventType.STEP_FINISHED,
768
763
  stepName: stepId || genId(),
769
764
  stepId: stepId || genId(),
770
765
  model,
771
- timestamp,
766
+ timestamp: Date.now(),
772
767
  delta,
773
768
  content: accumulatedThinking,
774
- })
769
+ }
775
770
  } else if (
776
771
  (event.delta as { type: string }).type === 'signature_delta'
777
772
  ) {
@@ -783,43 +778,43 @@ export class AnthropicTextAdapter<
783
778
  // Emit TOOL_CALL_START on first args delta
784
779
  if (!existing.started) {
785
780
  existing.started = true
786
- yield asChunk({
787
- type: 'TOOL_CALL_START',
781
+ yield {
782
+ type: EventType.TOOL_CALL_START,
788
783
  toolCallId: existing.id,
789
784
  toolCallName: existing.name,
790
785
  toolName: existing.name,
791
786
  model,
792
- timestamp,
787
+ timestamp: Date.now(),
793
788
  index: currentToolIndex,
794
- })
789
+ }
795
790
  }
796
791
 
797
792
  existing.input += event.delta.partial_json
798
793
 
799
- yield asChunk({
800
- type: 'TOOL_CALL_ARGS',
794
+ yield {
795
+ type: EventType.TOOL_CALL_ARGS,
801
796
  toolCallId: existing.id,
802
797
  model,
803
- timestamp,
798
+ timestamp: Date.now(),
804
799
  delta: event.delta.partial_json,
805
800
  args: existing.input,
806
- })
801
+ }
807
802
  }
808
803
  }
809
804
  } else if (event.type === 'content_block_stop') {
810
805
  if (currentBlockType === 'thinking') {
811
806
  // Emit signature so it can be replayed in multi-turn context
812
807
  if (accumulatedSignature && stepId) {
813
- yield asChunk({
814
- type: 'STEP_FINISHED',
808
+ yield {
809
+ type: EventType.STEP_FINISHED,
815
810
  stepName: stepId,
816
811
  stepId,
817
812
  model,
818
- timestamp,
813
+ timestamp: Date.now(),
819
814
  delta: '',
820
815
  content: accumulatedThinking,
821
816
  signature: accumulatedSignature,
822
- })
817
+ }
823
818
  }
824
819
  } else if (currentBlockType === 'tool_use') {
825
820
  const existing = toolCallsMap.get(currentToolIndex)
@@ -827,15 +822,15 @@ export class AnthropicTextAdapter<
827
822
  // If tool call wasn't started yet (no args), start it now
828
823
  if (!existing.started) {
829
824
  existing.started = true
830
- yield asChunk({
831
- type: 'TOOL_CALL_START',
825
+ yield {
826
+ type: EventType.TOOL_CALL_START,
832
827
  toolCallId: existing.id,
833
828
  toolCallName: existing.name,
834
829
  toolName: existing.name,
835
830
  model,
836
- timestamp,
831
+ timestamp: Date.now(),
837
832
  index: currentToolIndex,
838
- })
833
+ }
839
834
  }
840
835
 
841
836
  // Emit TOOL_CALL_END
@@ -847,15 +842,15 @@ export class AnthropicTextAdapter<
847
842
  parsedInput = {}
848
843
  }
849
844
 
850
- yield asChunk({
851
- type: 'TOOL_CALL_END',
845
+ yield {
846
+ type: EventType.TOOL_CALL_END,
852
847
  toolCallId: existing.id,
853
848
  toolCallName: existing.name,
854
849
  toolName: existing.name,
855
850
  model,
856
- timestamp,
851
+ timestamp: Date.now(),
857
852
  input: parsedInput,
858
- })
853
+ }
859
854
 
860
855
  // Reset so a new TEXT_MESSAGE_START is emitted if text follows tool calls
861
856
  hasEmittedTextMessageStart = false
@@ -863,12 +858,12 @@ export class AnthropicTextAdapter<
863
858
  } else {
864
859
  // Emit TEXT_MESSAGE_END only for text blocks (not tool_use blocks)
865
860
  if (hasEmittedTextMessageStart && accumulatedContent) {
866
- yield asChunk({
867
- type: 'TEXT_MESSAGE_END',
861
+ yield {
862
+ type: EventType.TEXT_MESSAGE_END,
868
863
  messageId,
869
864
  model,
870
- timestamp,
871
- })
865
+ timestamp: Date.now(),
866
+ }
872
867
  }
873
868
  }
874
869
  currentBlockType = null
@@ -876,32 +871,32 @@ export class AnthropicTextAdapter<
876
871
  // Close reasoning events if still open
877
872
  if (reasoningMessageId && !hasClosedReasoning) {
878
873
  hasClosedReasoning = true
879
- yield asChunk({
880
- type: 'REASONING_MESSAGE_END',
874
+ yield {
875
+ type: EventType.REASONING_MESSAGE_END,
881
876
  messageId: reasoningMessageId,
882
877
  model,
883
- timestamp,
884
- })
885
- yield asChunk({
886
- type: 'REASONING_END',
878
+ timestamp: Date.now(),
879
+ }
880
+ yield {
881
+ type: EventType.REASONING_END,
887
882
  messageId: reasoningMessageId,
888
883
  model,
889
- timestamp,
890
- })
884
+ timestamp: Date.now(),
885
+ }
891
886
  }
892
887
 
893
888
  // Only emit RUN_FINISHED from message_stop if message_delta didn't already emit one.
894
889
  // message_delta carries the real stop_reason (tool_use, end_turn, etc.),
895
890
  // while message_stop is just a completion signal.
896
891
  if (!hasEmittedRunFinished) {
897
- yield asChunk({
898
- type: 'RUN_FINISHED',
892
+ yield {
893
+ type: EventType.RUN_FINISHED,
899
894
  runId,
900
895
  threadId,
901
896
  model,
902
- timestamp,
897
+ timestamp: Date.now(),
903
898
  finishReason: 'stop',
904
- })
899
+ }
905
900
  }
906
901
  } else if (event.type === 'message_delta') {
907
902
  if (event.delta.stop_reason) {
@@ -910,28 +905,28 @@ export class AnthropicTextAdapter<
910
905
  // Close reasoning events if still open
911
906
  if (reasoningMessageId && !hasClosedReasoning) {
912
907
  hasClosedReasoning = true
913
- yield asChunk({
914
- type: 'REASONING_MESSAGE_END',
908
+ yield {
909
+ type: EventType.REASONING_MESSAGE_END,
915
910
  messageId: reasoningMessageId,
916
911
  model,
917
- timestamp,
918
- })
919
- yield asChunk({
920
- type: 'REASONING_END',
912
+ timestamp: Date.now(),
913
+ }
914
+ yield {
915
+ type: EventType.REASONING_END,
921
916
  messageId: reasoningMessageId,
922
917
  model,
923
- timestamp,
924
- })
918
+ timestamp: Date.now(),
919
+ }
925
920
  }
926
921
 
927
922
  switch (event.delta.stop_reason) {
928
923
  case 'tool_use': {
929
- yield asChunk({
930
- type: 'RUN_FINISHED',
924
+ yield {
925
+ type: EventType.RUN_FINISHED,
931
926
  runId,
932
927
  threadId,
933
928
  model,
934
- timestamp,
929
+ timestamp: Date.now(),
935
930
  finishReason: 'tool_calls',
936
931
  usage: {
937
932
  promptTokens: event.usage.input_tokens || 0,
@@ -940,15 +935,14 @@ export class AnthropicTextAdapter<
940
935
  (event.usage.input_tokens || 0) +
941
936
  (event.usage.output_tokens || 0),
942
937
  },
943
- })
938
+ }
944
939
  break
945
940
  }
946
941
  case 'max_tokens': {
947
- yield asChunk({
948
- type: 'RUN_ERROR',
949
- runId,
942
+ yield {
943
+ type: EventType.RUN_ERROR,
950
944
  model,
951
- timestamp,
945
+ timestamp: Date.now(),
952
946
  message:
953
947
  'The response was cut off because the maximum token limit was reached.',
954
948
  code: 'max_tokens',
@@ -957,16 +951,16 @@ export class AnthropicTextAdapter<
957
951
  'The response was cut off because the maximum token limit was reached.',
958
952
  code: 'max_tokens',
959
953
  },
960
- })
954
+ }
961
955
  break
962
956
  }
963
957
  default: {
964
- yield asChunk({
965
- type: 'RUN_FINISHED',
958
+ yield {
959
+ type: EventType.RUN_FINISHED,
966
960
  runId,
967
961
  threadId,
968
962
  model,
969
- timestamp,
963
+ timestamp: Date.now(),
970
964
  finishReason: 'stop',
971
965
  usage: {
972
966
  promptTokens: event.usage.input_tokens || 0,
@@ -975,7 +969,7 @@ export class AnthropicTextAdapter<
975
969
  (event.usage.input_tokens || 0) +
976
970
  (event.usage.output_tokens || 0),
977
971
  },
978
- })
972
+ }
979
973
  }
980
974
  }
981
975
  }
@@ -988,18 +982,17 @@ export class AnthropicTextAdapter<
988
982
  error,
989
983
  source: 'anthropic.processAnthropicStream',
990
984
  })
991
- yield asChunk({
992
- type: 'RUN_ERROR',
993
- runId,
985
+ yield {
986
+ type: EventType.RUN_ERROR,
994
987
  model,
995
- timestamp,
988
+ timestamp: Date.now(),
996
989
  message: err.message || 'Unknown error occurred',
997
990
  code: err.code || String(err.status),
998
991
  error: {
999
992
  message: err.message || 'Unknown error occurred',
1000
993
  code: err.code || String(err.status),
1001
994
  },
1002
- })
995
+ }
1003
996
  }
1004
997
  }
1005
998
  }
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