@@ -25,11 +25,12 @@ async Task<ChatResponse> IChatClient.GetResponseAsync(
25
25
{
26
26
CreateMessageParams request = CreateRequest ( messages , options ) ;
27
27
28
- var response = await this . Messages . MessagesPostAsync ( request , anthropicVersion : "2023-06-01" , cancellationToken ) . ConfigureAwait ( false ) ;
28
+ var response = await this . Messages . MessagesPostAsync ( request , cancellationToken : cancellationToken ) . ConfigureAwait ( false ) ;
29
29
30
30
ChatMessage responseMessage = new ( )
31
31
{
32
- Role = response . Role == MessageRole . Assistant ? ChatRole . Assistant : ChatRole . User ,
32
+ MessageId = response . Id ,
33
+ Role = ChatRole . Assistant ,
33
34
RawRepresentation = response ,
34
35
} ;
35
36
@@ -38,47 +39,37 @@ async Task<ChatResponse> IChatClient.GetResponseAsync(
38
39
( responseMessage . AdditionalProperties ??= [ ] ) [ nameof ( response . StopSequence ) ] = response . StopSequence ;
39
40
}
40
41
41
- // if (response.Content.Value1 is string stringContents)
42
- // {
43
- // responseMessage.Contents.Add(new TextContent(stringContents));
44
- // }
45
- //else if (response.Content.Value2 is IList<Block> blocks)
42
+ foreach ( var block in response . Content )
46
43
{
47
- foreach ( var block in response . Content )
44
+ if ( block . IsText )
48
45
{
49
- if ( block . IsText )
46
+ responseMessage . Contents . Add ( new TextContent ( block . Text ! . Text ) { RawRepresentation = block } ) ;
47
+ }
48
+ else if ( block . IsThinking )
49
+ {
50
+ responseMessage . Contents . Add ( new TextReasoningContent ( block . Thinking ! . Thinking )
50
51
{
51
- responseMessage . Contents . Add ( new TextContent ( block . Text ! . Text ) { RawRepresentation = block . Text } ) ;
52
- }
53
- // else if (block.IsImage)
54
- // {
55
- // responseMessage.Contents.Add(new ImageContent(
56
- // block.Image!.Source.Data,
57
- // block.Image!.Source.MediaType switch
58
- // {
59
- // ImageBlockSourceMediaType.ImagePng => "image/png",
60
- // ImageBlockSourceMediaType.ImageGif => "image/gif",
61
- // ImageBlockSourceMediaType.ImageWebp => "image/webp",
62
- // _ => "image/jpeg",
63
- // })
64
- // {
65
- // RawRepresentation = block.Image
66
- // });
67
- // }
68
- else if ( block . IsToolUse )
52
+ AdditionalProperties = new ( ) { [ nameof ( RequestThinkingBlock . Signature ) ] = block . Thinking . Signature } ,
53
+ RawRepresentation = block ,
54
+ } ) ;
55
+ }
56
+ else if ( block . IsToolUse )
57
+ {
58
+ responseMessage . Contents . Add ( new FunctionCallContent (
59
+ block . ToolUse ! . Id ,
60
+ block . ToolUse ! . Name ,
61
+ block . ToolUse ! . Input is JsonElement e ? ( IDictionary < string , object ? > ? ) e . Deserialize (
62
+ JsonSerializerContext . Options . GetTypeInfo ( typeof ( Dictionary < string , object ? > ) ) ) :
63
+ null )
69
64
{
70
- responseMessage . Contents . Add ( new FunctionCallContent (
71
- block . ToolUse ! . Id ,
72
- block . ToolUse ! . Name ,
73
- block . ToolUse ! . Input is JsonElement e ? ( IDictionary < string , object ? > ? ) e . Deserialize (
74
- JsonSerializerContext . Options . GetTypeInfo ( typeof ( Dictionary < string , object ? > ) ) ) :
75
- null ) ) ;
76
- }
65
+ RawRepresentation = block
66
+ } ) ;
77
67
}
78
68
}
79
69
80
70
ChatResponse completion = new ( responseMessage )
81
71
{
72
+ RawRepresentation = response ,
82
73
ResponseId = response . Id ,
83
74
ModelId = response . Model ,
84
75
FinishReason = response . StopReason switch
@@ -99,15 +90,15 @@ async Task<ChatResponse> IChatClient.GetResponseAsync(
99
90
TotalTokenCount = u . InputTokens + u . OutputTokens ,
100
91
} ;
101
92
102
- // if (u.CacheCreationInputTokens is not null )
103
- // {
104
- // (completion.Usage.AdditionalProperties ??= [])[nameof(u.CacheCreationInputTokens)] = u.CacheCreationInputTokens ;
105
- // }
106
- //
107
- // if (u.CacheReadInputTokens is not null )
108
- // {
109
- // (completion.Usage.AdditionalProperties ??= [])[nameof(u.CacheReadInputTokens)] = u.CacheReadInputTokens ;
110
- // }
93
+ if ( u . CacheCreationInputTokens is int cacheCreationTokens )
94
+ {
95
+ ( completion . Usage . AdditionalCounts ??= [ ] ) [ nameof ( u . CacheCreationInputTokens ) ] = cacheCreationTokens ;
96
+ }
97
+
98
+ if ( u . CacheReadInputTokens is int cacheReadTokens )
99
+ {
100
+ ( completion . Usage . AdditionalCounts ??= [ ] ) [ nameof ( u . CacheReadInputTokens ) ] = cacheReadTokens ;
101
+ }
111
102
}
112
103
113
104
return completion ;
@@ -119,39 +110,26 @@ async IAsyncEnumerable<ChatResponseUpdate> IChatClient.GetStreamingResponseAsync
119
110
CreateMessageParams request = CreateRequest ( messages , options ) ;
120
111
121
112
IAsyncEnumerable < MessageStreamEvent > enumerable =
122
- CreateMessageAsStreamAsync ( request , anthropicVersion : "2023-06-01" , cancellationToken ) ;
113
+ CreateMessageAsStreamAsync ( request , cancellationToken : cancellationToken ) ;
123
114
124
115
await foreach ( var response in enumerable . ConfigureAwait ( false ) )
125
116
{
126
- var chatResponseUpdate = new ChatResponseUpdate ( ) ;
117
+ ChatResponseUpdate chatResponseUpdate = new ( ) ;
118
+
127
119
if ( response . IsContentBlockDelta )
128
120
{
129
121
var delta = response . ContentBlockDelta ! . Delta ;
130
122
if ( delta . IsTextDelta )
131
123
{
132
- chatResponseUpdate . Contents . Add ( new TextContent ( delta . TextDelta ! . Text ) { RawRepresentation = delta . TextDelta ! . Text } ) ;
124
+ chatResponseUpdate . Contents . Add ( new TextContent ( delta . TextDelta ! . Text ) { RawRepresentation = response } ) ;
133
125
}
134
126
}
135
127
136
128
yield return chatResponseUpdate ;
137
- // yield return new ChatResponseUpdate
138
- // {
139
- // //AdditionalProperties = response.AdditionalProperties,
140
- // //AuthorName = choice.AuthorName,
141
- // ChatThreadId = response.ChatThreadId,
142
- // ChoiceIndex = i,
143
- // ResponseId = response.ResponseId,
144
- // Contents = choice.Contents,
145
- // CreatedAt = response.CreatedAt,
146
- // FinishReason = response.FinishReason,
147
- // ModelId = response.ModelId,
148
- // RawRepresentation = choice.RawRepresentation,
149
- // Role = choice.Role,
150
- // };
151
129
}
152
130
}
153
131
154
- private static CreateMessageParams CreateRequest ( IEnumerable < ChatMessage > chatMessages , ChatOptions ? options )
132
+ private CreateMessageParams CreateRequest ( IEnumerable < ChatMessage > chatMessages , ChatOptions ? options )
155
133
{
156
134
string ? systemMessage = null ;
157
135
@@ -177,21 +155,60 @@ private static CreateMessageParams CreateRequest(IEnumerable<ChatMessage> chatMe
177
155
blocks . Add ( new InputContentBlock ( new RequestTextBlock { Text = tc . Text } ) ) ;
178
156
break ;
179
157
180
- case DataContent ic when ic . HasTopLevelMediaType ( "image" ) :
158
+ case TextReasoningContent trc :
159
+ blocks . Add ( new InputContentBlock ( new RequestThinkingBlock
160
+ {
161
+ Thinking = trc . Text ,
162
+ Signature = trc . AdditionalProperties ? . TryGetValue ( nameof ( RequestThinkingBlock . Signature ) , out string ? sig ) is true ? sig : "" ,
163
+ } ) ) ;
164
+ break ;
165
+
166
+ case DataContent dc when dc . HasTopLevelMediaType ( "image" ) :
181
167
blocks . Add ( new InputContentBlock ( new RequestImageBlock
182
168
{
183
169
Source = new Base64ImageSource
184
170
{
185
- MediaType = ic . MediaType switch
171
+ MediaType = dc . MediaType switch
186
172
{
187
173
"image/png" => Base64ImageSourceMediaType . ImagePng ,
188
174
"image/gif" => Base64ImageSourceMediaType . ImageGif ,
189
175
"image/webp" => Base64ImageSourceMediaType . ImageWebp ,
190
176
_ => Base64ImageSourceMediaType . ImageJpeg ,
191
177
} ,
192
- Data = ic . Data . ToArray ( ) ?? [ ] , //Convert.ToBase64String(ic.Data?.ToArray() ?? []) ,
178
+ Data = dc . Data . ToArray ( ) ?? [ ] ,
193
179
Type = Base64ImageSourceType . Base64 ,
194
- }
180
+ } ,
181
+ } ) ) ;
182
+ break ;
183
+
184
+ case DataContent dc when dc . MediaType . Equals ( "application/pdf" , StringComparison . OrdinalIgnoreCase ) :
185
+ blocks . Add ( new InputContentBlock ( new RequestDocumentBlock
186
+ {
187
+ Source = new Base64PDFSource
188
+ {
189
+ MediaType = Base64PDFSourceMediaType . ApplicationPdf ,
190
+ Data = dc . Data . ToArray ( ) ?? [ ] ,
191
+ } ,
192
+ } ) ) ;
193
+ break ;
194
+
195
+ case UriContent uc when uc . HasTopLevelMediaType ( "image" ) :
196
+ blocks . Add ( new InputContentBlock ( new RequestImageBlock
197
+ {
198
+ Source = new URLImageSource
199
+ {
200
+ Url = uc . Uri . ToString ( ) ,
201
+ } ,
202
+ } ) ) ;
203
+ break ;
204
+
205
+ case UriContent uc when uc . MediaType . Equals ( "application/pdf" , StringComparison . OrdinalIgnoreCase ) :
206
+ blocks . Add ( new InputContentBlock ( new RequestDocumentBlock
207
+ {
208
+ Source = new URLPDFSource
209
+ {
210
+ Url = uc . Uri . ToString ( ) ,
211
+ } ,
195
212
} ) ) ;
196
213
break ;
197
214
@@ -225,36 +242,78 @@ private static CreateMessageParams CreateRequest(IEnumerable<ChatMessage> chatMe
225
242
}
226
243
}
227
244
228
- var request = new CreateMessageParams
245
+ CreateMessageParams ? request = options ? . RawRepresentationFactory ? . Invoke ( this ) as CreateMessageParams ;
246
+ if ( request is not null )
229
247
{
230
- MaxTokens = options ? . MaxOutputTokens ?? 250 ,
231
- Messages = messages ,
232
- Model = options ? . ModelId ?? string . Empty ,
233
- StopSequences = options ? . StopSequences ,
234
- System = systemMessage is not null ? new ( systemMessage ) : null ,
235
- Temperature = options ? . Temperature ,
236
- TopP = options ? . TopP ,
237
- TopK = options ? . TopK ,
238
- ToolChoice =
239
- options ? . Tools is not { Count : > 0 } ? null :
240
- options ? . ToolMode is AutoChatToolMode ? new ToolChoice ( new ToolChoiceAuto ( ) ) :
241
- options ? . ToolMode is RequiredChatToolMode r
242
- ? r . RequiredFunctionName is not null
243
- ? new ToolChoice ( new ToolChoiceTool
244
- {
245
- Name = r . RequiredFunctionName ,
246
- } )
247
- : new ToolChoice ( new ToolChoiceAny ( ) )
248
- : ( ToolChoice ? ) null ,
249
- Tools = options ? . Tools is IList < AITool > tools ?
250
- tools . OfType < AIFunction > ( ) . Select ( f => new global ::Anthropic . OneOf < global ::Anthropic . Tool , global ::Anthropic . BashTool20250124 , global ::Anthropic . TextEditor20250124 , global ::Anthropic . WebSearchTool20250305 > ( new Tool
248
+ request . Model = options ? . ModelId ?? string . Empty ;
249
+ if ( request . Messages is null )
250
+ {
251
+ request . Messages = messages ;
252
+ }
253
+ else
254
+ {
255
+ foreach ( var message in messages )
251
256
{
252
- Name = f . Name ,
253
- Description = f . Description ,
254
- InputSchema = CreateSchema ( f ) ,
255
- } ) ) . ToList ( ) :
256
- null ,
257
- } ;
257
+ request . Messages . Add ( message ) ;
258
+ }
259
+ }
260
+ }
261
+ else
262
+ {
263
+ request = new ( )
264
+ {
265
+ Model = options ? . ModelId ?? string . Empty ,
266
+ MaxTokens = options ? . MaxOutputTokens ?? 250 ,
267
+ Messages = messages ,
268
+ } ;
269
+ }
270
+
271
+ request . StopSequences ??= options ? . StopSequences ;
272
+ if ( systemMessage is not null )
273
+ {
274
+ request . System ??= new ( systemMessage ) ;
275
+ }
276
+ request . Temperature ??= options ? . Temperature ;
277
+ request . TopP ??= options ? . TopP ;
278
+ request . TopK ??= options ? . TopK ;
279
+
280
+ request . ToolChoice ??=
281
+ options ? . Tools is not { Count : > 0 } ? null :
282
+ options ? . ToolMode is AutoChatToolMode ? new ToolChoice ( new ToolChoiceAuto ( ) ) :
283
+ options ? . ToolMode is RequiredChatToolMode r
284
+ ? r . RequiredFunctionName is not null
285
+ ? new ToolChoice ( new ToolChoiceTool
286
+ {
287
+ Name = r . RequiredFunctionName ,
288
+ } )
289
+ : new ToolChoice ( new ToolChoiceAny ( ) )
290
+ : ( ToolChoice ? ) null ;
291
+
292
+ if ( options ? . Tools is { Count : > 0 } aitools )
293
+ {
294
+ var tools = request . Tools ?? [ ] ;
295
+ request . Tools = tools ;
296
+
297
+ foreach ( var tool in aitools )
298
+ {
299
+ switch ( tool )
300
+ {
301
+ case AIFunction f :
302
+ tools . Add ( new Tool
303
+ {
304
+ Name = f . Name ,
305
+ Description = f . Description ,
306
+ InputSchema = CreateSchema ( f ) ,
307
+ } ) ;
308
+ break ;
309
+
310
+ case HostedWebSearchTool ws :
311
+ tools . Add ( new WebSearchTool20250305 ( ) ) ;
312
+ break ;
313
+ }
314
+ }
315
+ }
316
+
258
317
return request ;
259
318
}
260
319
0 commit comments